为什么typedef结构会产生链接失败

时间:2014-02-04 10:53:47

标签: c++ language-lawyer

所以我有一段看起来像这样的代码。

typedef struct {
  int foo;
  int bar;
  void foobar(int, char*);
} mystruct;

void mystruct::foobar(int x, char* y) { return; }

mystruct obj;
obj.foobar(17, "X");

这一切都完美地编译,链接和运行。除非它没有。在一个编译器上工作,在另一个编译器(Android GCC)上它失败并出现链接错误:不满意的引用。

如果我这样改变它,它会编译和链接。

struct mystruct {
  int foo;
  int bar;
  void foobar(int, char*);
};

我想我知道为什么,但我无法正确解释,我无法在标准中找到它。任何人都可以向我解释并找到适当的参考吗?

编辑:我认为所有人都很清楚这是C ++代码。我标记了它; struct中的函数无效C;但只是要清楚文件有CPP扩展名,编译器将其视为C ++。

编辑:回答者注意到调用是文字,因此是const,但是arg是非const的。这不是一个关键因素,因为(a)编译器传递它(b)链接失败,无论参数类型如何。

编辑:我的理论是,这与传递给链接器的匿名结构类型有关,因此单独编译的声明和调用不匹配。看起来这可能不正确,在这种情况下,它可能只是一个微妙的编译器错误。

编辑:出于好奇,有人可以重现这种行为吗?实际的编译器是Android NDK,最近的下载,以及随之而来的任何GCC版本。如果其他编译器确实/没有这个问题,那可能就是答案。

5 个答案:

答案 0 :(得分:5)

我认为这是一个编译错误。以下更极端的例子仍然可以:

typedef struct { void f(); } f;
void f::f() { }

来自GCC buglist。即您可以使用typedef名称来定义成员函数,即使该成员函数与typedef具有相同的名称。

答案 1 :(得分:4)

C ++ 11,9.3 / 5

  

如果成员函数的定义在词法定义之外是词法定义,则成员函数名称应使用::运算符通过其类名进行限定

在第一个示例中,mystruct不是类名。

答案 2 :(得分:1)

基本上,结构的名称位于{bracket之前的第一行。最后一个字是由typedef重命名的另一个名称。

它也需要使用:

typedef struct mystruct{int a;int b;void foobar(int,char*)} othername;
void mystruct::foobar(int,char*){}

答案 3 :(得分:1)

typedef中匿名结构的习惯用法是我在第一次学习C时经常使用的习惯。例如以下几行是C中类型的有效描述

typedef struct
{
   char * characters;
   int length;
} String;

如果gcc对此窒息,那么gcc就错了。

答案 4 :(得分:-2)

似乎你在混合使用C和C ++。首先,如果您希望代码是C ++,那么您肯定必须:

void foobar(int, const char*);

因为“X”是类型(const char *),而不是(char *)。

其次,如果您希望代码为C,则不能在结构中使用函数。在C中只允许指向函数的指针。所以,

typedef struct {
    void (*foo)(void);
} X;

您的第一个代码在C ++代码中有效,但它可能与您真正想要的不同。

typedef struct {...} A;在C ++中是一个带有typedef的无名结构。它类似于:

 struct A {
     void foo();
 }
 typedef A B;
 void B::foo() { }

我认为这不是一个有效的C ++构造。删除“A”您完全得到了代码:

 typedef struct {
     void foo();
 } B;
 void B::foo() { }