这里有几件事情需要注意。首先,正如其他人所说,编译器对未知类型的抱怨可能是因为在使用它们之前需要先声明类型。但更重要的是要理解以下3个方面的语法:
- 结构体类型的定义
- 结构体变量的定义和声明
- typedef(类型定义)
(请注意,在C编程语言中,定义和声明通常同时发生,因此本质上是相同的。在许多其他语言中,情况并非如此。请参见下面的脚注以获取更多详细信息。)
在定义结构体时,结构体可以被标记(命名),也可以是未加标记的。如果未加标记,则必须立即使用该结构体(将在下文进一步解释其含义)。
struct Name {
...
};
这定义了一个名为“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++中做的那样)。以下是首先定义结构体,然后typedef结构体的示例:
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,并且您没有为typedef提供NewTypeName。这就是为什么编译器不喜欢您编写的代码的原因(尽管编译器的消息有点难以理解,因为它不太确定您做错了什么)。
现在,正如我上面所指出的,如果您在定义结构类型时没有标记(命名)它,则必须立即使用它,以定义变量:
struct {
...
} myNameStruct;
或者您可以在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没有被保留,也没有被特别解析或被编译器注意到,它只是一个在C中定义新类型时遵循的约定。在C++中,许多人使用以大写字母开头的约定来开始类型名称,例如MyNewType(与C约定的my_new_type_t相对应)。祝好。
关于声明和定义的脚注:首先特别感谢@CJM提出澄清编辑,尤其是关于这些术语的使用方面。
通常声明和定义以下项:类型、变量和函数。
- 声明仅为编译器提供符号名称和“类型”信息。
- 定义为编译器提供项目的全部细节:
- 在类型的情况下,定义为编译器提供名称和该类型的详细结构。
- 在变量的情况下,定义告诉编译器分配内存(在哪里以及多少)以创建该变量的实例。
一般来说,在由多个文件组成的程序中,变量、类型和函数可以在许多文件中进行声明,但每个文件可能只有一个定义。
在许多编程语言(例如C++)中,声明和定义很容易分开。这使得类型、变量和函数可以进行“前向声明”,从而可以在稍后定义这些项之前编译文件。然而,在C编程语言中,变量的声明和定义是同一件事情。(据我所知,C编程语言中唯一的例外是使用关键字extern允许变量进行声明而无需定义。)正因为如此,在此答案的先前编辑中,我提到了结构体的“定义”和“结构体[变量]的声明”,其中“结构体[变量]的声明”的意义被理解为创建该结构体的实例(变量)。
Author
结构体怎么可能就能移除error:unknown type name ‘Book’
错误呢?请查看 这里,其中明确说明了使用 typedef 定义结构体和直接定义结构体的区别。 - Dayal rai