C: имя структуры typedef { ... }; VS имя структуры typedef { ... };

как говорит название, у меня есть этот код :

typedef struct Book{
    int id;
    char title[256];
    char summary[2048];
    int numberOfAuthors;
    struct Author *authors;
};


typedef struct Author{
    char firstName[56];
    char lastName[56];
};


typedef struct Books{
    struct Book *arr;
    int numberOfBooks;
};

Я получаю эти ошибки от gcc:

bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:9:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:15:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:21:2: error: unknown type name ‘Book’
bookstore.c:23:1: warning: useless storage class specifier in empty declaration [enabled by default]

Если я изменю typedefs следующим образом:

typedef struct{
    char firstName[56];
    char lastName[56];
} Author;

тогда никаких предупреждений и ошибок нет. Обыскав http://www.amazon.com/C-Programming-Language-2nd-Edition/dp/0131103628 и пару часов гуглить я не могу понять, почему первая реализация не будет работать.

4 ответов


здесь происходит несколько вещей. Во-первых, как говорили другие, жалоба компилятора на неизвестный тип может быть связана с тем, что вам нужно определить типы перед их использованием. Более важным, однако, является понимание синтаксиса 3 вещей: (1) определение структуры, (2) объявление структуры и (3) typedef.

при определении структуры структура может быть названа или неназвана (если неназвана, то она должна использоваться немедленно (объяснит, что это значит дальше ниже.))

struct Name {
   ...
};

это определяет тип под названием "Имя структуры", который затем может использоваться для объявления переменной структуры:

struct Name myNameStruct;

объявляется переменная myNameStruct, который является struct типа struct Name.

вы также можете определить структуру и одновременно объявить переменную структуры:

struct Name {
   ...
} myNameStruct;

как и раньше, это объявляет переменную с именем myNameStruct, который является struct типа struct Name ... но он делает это в то же время определяет тип struct Name.
Тип можно использовать снова для объявления другой переменной:

struct Name myOtherNameStruct;

теперь typedef-это просто способ псевдонима типа с определенным именем:

typedef OldTypeName NewTypeName;

учитывая выше typedef, в любое время вы используете NewTypeName это то же самое, что и использование OldTypeName. в языке программирования C это особенно полезно для структур, потому что это дает вам возможность оставить слово "struct" при объявлении переменных этого тип и рассматривать имя структуры просто как тип сам по себе (как мы делаем в C++). Вот пример, который сначала определяет структуру, а затем typedefs struct:

struct Name {
   ...
};

typedef struct Name Name_t;

в приведенном выше OldTypeName является struct Name и NewTypeName Name_t. Итак, теперь, чтобы объявить переменную типа struct Name, вместо написания:

struct Name myNameStruct;

я могу просто написать:

Name_t myNameStruct;

Примечание кроме того, typedef можно комбинировать с определением структуры, и это то, что вы делаете в коде:

typedef struct {
   ...
} Name_t;

это также можно сделать, называя структуру, но это излишне:

typedef struct Name {
   ...
} Name_t;

ОБРАТИТЕ ВНИМАНИЕ: в синтаксисе выше, так как вы начали с "typedef", то весь оператор является typedef оператор, в котором OldTypeName оказывается определением структуры. Поэтому компилятор интерпретирует имя после правая фигурная скобка } как NewTypeName ... это не имя переменной (как и в синтаксисе без typedef, в этом случае вы одновременно определяете структуру и объявляете переменную структуры).

кроме того, если вы указываете typedef, но оставляете Name_t в конце, то вы фактически создали неполный оператор typedef, потому что компилятор считает все, что в "struct Name { ... } " как OldTypeName, и вы не предоставляете NewTypeName для typedef. Вот почему компилятор не доволен кодом, как вы его написали (хотя сообщения компилятора довольно загадочны, потому что он не совсем уверен, что вы сделали неправильно).

теперь, как я уже отмечал выше, если вы не называете тип структуры в то время, когда вы его определяете, то вы должны немедленно использовать его либо для объявления переменной:

struct {
   ...
} myNameStruct;  // declares myNameStruct as a variable with this struct
                 // definition, but the definition cannot be re-used.

или вы можете использовать неназванный тип структуры в typedef:

typedef struct {
   ...
} Name_t;

этот финал синтаксис-это то, что вы на самом деле делали, когда писали:

typedef struct{
   char firstName[56];
   char lastName[56];
} Author;

и компилятор был счастлив. HTH.

относительно комментария / вопроса о суффиксе _t:

_t суффикс является соглашением, чтобы указать людям, читающим код, что символическое имя с _t является именем типа (в отличие от имени переменной). Компилятор не анализирует и не осознает _t.

C89, и в частности C99, стандартные библиотеки определили много типы и решили использовать _t для имен этих типов. Например, стандарт C89 определяет wchar_t, off_t, ptrdiff_t. Стандарт C99 определяет множество дополнительных типов, таких как uintptr_t, intmax_t, int8_t, uint_least16_t, uint_fast32_t и т. д. Но _t не зарезервирован, не специально проанализирован и не замечен компилятором, это просто соглашение, которое хорошо следовать, когда вы определяете новые типы (через typedef) в C. В C++ многие люди используют Соглашение для запуска имен типов в верхнем регистре, например, MyNewType (в отличие от соглашения C my_new_type_t ). HTH


синтаксис для typedef следующим образом:

typedef old_type new_type

С первой попытки вы определили struct Book тип и не Book. Другими словами, ваш тип данных называется struct Book, а не Book.

во второй форме вы использовали правильный синтаксис typedef, поэтому компилятор распознает тип Book.


вам просто нужно определить автора перед определением книги.

вы используете автора в книге, поэтому его нужно определить раньше.


Я думаю, это поможет вам понять. http://www.tutorialspoint.com/cprogramming/c_typedef.htm

bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:21:2: error: unknown type name ‘Book’

эти производятся, потому что вы должны определить их, прежде чем использовать их. Переместите структуру "автор" и " книги "над структурой"книга". Это все решит.

также предупреждение, которое вы получаете, объясняет, почему существует проблема, компилятор определяет "typedef struct Author" как не необходимый, потому что вы неправильно typedef struct таким образом, для компилятора нет ничего полезного для "чтения".

поскольку вы уже знаете ответ должен быть в таком виде

typedef struct {
 ...
 ... 
 ...
} struct-name;

придерживаться этого.