Подтвердить что ты не робот

C: typedef struct name {...}; VS typedef struct {...} name;

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

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 и пару часов погуглив, я не могу понять, почему первая реализация не сработает.

4b9b3361

Ответ 1

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

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

struct Name {
   ...
};

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

struct Name myNameStruct;

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

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

struct Name {
   ...
} myNameStruct;

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

struct Name myOtherNameStruct;

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

typedef OldTypeName NewTypeName;

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

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;

NOTE WELL: В приведенном выше синтаксисе, поскольку вы начали с "typedef", весь оператор является оператором typedef, в котором OldTypeName является определением структуры. Поэтому компилятор интерпретирует имя, идущее после правой фигурной скобки} как NewTypeName... это НЕ имя переменной (как это было бы в синтаксисе без typedef, в этом случае вы определяете структуру и объявляете переменную структуры). в то же время).

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

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

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;

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

Относительно комментария/вопроса о суффиксе _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). НТН

Ответ 2

Синтаксис typedef следующий:

typedef old_type new_type

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

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

Ответ 3

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

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

Ответ 4

Я думаю, это поможет вам понять. 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 {
 ...
 ... 
 ...
} struct-name;

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