Ответ 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). НТН