Почему структура typedef создает сбой связи
Итак, у меня есть кусок кода, который выглядит так.
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; но просто чтобы быть ясным, файл имеет расширение CPP, а компилятор рассматривает его как С++.
Изменить: ответчик заметил, что вызов является литералом и поэтому является константой, но arg не является константой. Это не является критическим фактором, потому что (a) компилятор передал его (b) связанный сбой, независимо от типов аргументов.
Изменить: Моя теория заключалась в том, что это связано с анонимными типами структуры, переданными компоновщику, так что декларация и вызов, скомпилированные отдельно, не совпадают. Кажется, это может быть неверно, и в этом случае это может быть просто тонкая ошибка компилятора.
Изменить: из любопытства, может ли кто-нибудь воспроизвести это поведение? Фактический компилятор - Android NDK, недавняя загрузка и любая версия GCC. Если у других компиляторов есть/нет этой проблемы, это может быть ответ.
Ответы
Ответ 1
Я думаю, что это ошибка компилятора. Следующий более экстремальный пример все еще в порядке:
typedef struct { void f(); } f;
void f::f() { }
Из GCC buglist. То есть вам разрешено использовать имя typedef для определения функции-члена, даже если эта функция-член имеет то же имя, что и typedef.
Ответ 2
С++ 11, 9.3/5
Если определение функции-члена лексически выходит за пределы его определения класса, имя функции-члена должно быть квалифицировано по имени его класса с помощью оператора ::
.
В первом примере mystruct
не является именем класса.
Ответ 3
В основном собственное имя структуры находится в первой строке перед {скобкой. Последнее слово - это другое имя, которое переименовано в typedef.
Также необходимо использовать так:
typedef struct mystruct{int a;int b;void foobar(int,char*)} othername;
void mystruct::foobar(int,char*){}
Ответ 4
Идиома анонимной структуры в typedef - это тот, который я использовал часто, когда я впервые узнал C. Например, следующие строки являются допустимым описанием типа в C
typedef struct
{
char * characters;
int length;
} String;
Если gcc дросселируется на этом, gcc ошибочно.
Ответ 5
Кажется, вы смешиваете C и С++. Во-первых, если вы хотите, чтобы код был С++, то вы определенно должны иметь:
void foobar(int, const char*);
потому что "X" имеет тип (const char *), а не (char *).
Во-вторых, если вы хотите, чтобы ваш код был C, вы не можете использовать функцию в структуре. Разрешены только указатели на функцию C. Итак,
typedef struct {
void (*foo)(void);
} X;
Ваш первый код действителен в коде С++, но это, вероятно, нечто иное, чем вы действительно хотите.
typedef struct {...} A; в С++ - структура без имен с typedef. Это что-то вроде:
struct A {
void foo();
}
typedef A B;
void B::foo() { }
Я не думаю, что это была бы правильная конструкция С++. Удаление "A" вы получили точно:
typedef struct {
void foo();
} B;
void B::foo() { }