正如标题所说,我有这段代码:
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]
如果我像这样更改typedef:
typedef struct{
char firstName[56];
char lastName[56];
} Author;
然后没有警告也没有错误发生。经过http://www.amazon.com/C-Programming-Language-2nd-Edition/dp/0131103628搜索和几个小时的谷歌搜索我无法弄清楚为什么第一个实现不起作用。
答案 0 :(得分:82)
这里有几件事情。首先,正如其他人所说,编译器对未知类型的抱怨可能是因为您需要在使用它们之前定义类型。更重要的是理解3件事的语法:(1)struct definition,(2)struct declaration,(3)typedef。
定义结构时,结构可以命名或未命名(如果未命名,则必须立即使用(将解释下面的内容)。
struct Name {
...
};
这定义了一个名为“struct Name”的类型,然后可以用它来声明一个struct变量:
struct Name myNameStruct;
这声明了一个名为myNameStruct
的变量,它是struct Name
类型的结构。
您还可以定义结构,并同时声明结构变量:
struct Name {
...
} myNameStruct;
和以前一样,这声明了一个名为myNameStruct
的变量,它是struct Name
类型的结构... 但它在定义类型的同时 { {1}}。
该类型可以再次用于声明另一个变量:
struct Name
现在,typedef只是一种为具有特定名称的类型添加别名的方法:
struct Name myOtherNameStruct;
鉴于上述typedef,只要您使用typedef OldTypeName NewTypeName;
,就会与使用NewTypeName
相同。 在C编程语言中,这对于结构体特别有用,因为它使您能够在声明该类型的变量时忽略单词“struct”,并将结构的名称简单地视为类型它自己(就像我们在C ++中所做的那样)。下面是一个示例,首先定义struct,然后键入struct struct:
OldTypeName
在上面的OldTypeName中是struct Name {
...
};
typedef struct Name Name_t;
,NewTypeName是struct Name
。所以现在,声明一个struct name类型的变量,而不是写:
Name_t
我可以简单地写一下:
struct Name myNameStruct;
另请注意,typedef可以与结构定义结合使用,这就是您在代码中所做的事情:
Name_t myNameStruct;
这也可以在命名结构时完成,但这是多余的:
typedef struct {
...
} Name_t;
注意:在上面的语法中,由于您已经开始使用“typedef”,因此整个语句是typedef struct Name {
...
} Name_t;
语句,其中OldTypeName恰好是结构定义。因此,编译器将右大括号}之后的名称解释为NewTypeName ...它是 NOT 变量名称(因为它将在没有typedef的语法中,在这种情况下,您将定义结构并同时声明结构变量)。
此外,如果您声明了typedef,但是在结束时不使用Name_t,那么您已经有效地创建了一个INCOMPLETE typedef语句,因为编译器会将“typedef
”中的所有内容视为OldTypeName,并且您没有为typedef提供NewTypeName。这就是编译器对代码不满意的原因(尽管编译器的消息相当神秘,因为它不太确定你做错了什么)。
现在,如上所述,如果在定义结构类型时没有命名结构类型,那么必须立即使用它来声明变量:
struct Name { ... }
或者您可以在typedef中使用未命名的结构类型:
struct {
...
} myNameStruct; // declares myNameStruct as a variable with this struct
// definition, but the definition cannot be re-used.
这个最终语法是你在写作时实际做的:
typedef struct {
...
} Name_t;
编译器很高兴。 HTH。
关于_t后缀的评论/问题:
_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中定义新类型(通过typedef)时。在C ++中,许多人使用约定来启动大写的类型名称,例如,MyNewType(而不是C约定my_new_type_t)。 HTH
答案 1 :(得分:5)
语法为typedef
如下:
typedef old_type new_type
在您第一次尝试时,您定义了struct Book
类型,不是 Book
。换句话说,您的数据类型称为struct Book
而不是Book
。
在第二种形式中,您使用了typedef
的正确语法,因此编译器会识别名为Book
的类型。
答案 2 :(得分:0)
您只需在定义Book之前定义作者。
您在Book中使用Author,因此需要先定义它。
答案 3 :(得分:0)
我认为会帮助你理解。 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;
坚持下去。
答案 4 :(得分:0)
想通过在实际声明变量时进行澄清来添加。
struct foo {
int a;
} my_foo;
定义foo
并立即声明my_foo
类型的变量struct foo
,这意味着您可以像这样my_foo.a = 5;
但是,因为typedef
的语法遵循typedef <oldname> <newname>
typedef struct bar {
int b;
} my_bar;
是 not ,声明类型为my_bar
的变量struct bar
,my_bar.b = 5;
是非法的 。相反,它以struct bar
的形式为my_bar
类型提供了一个新名称。您现在可以像这样用struct bar
声明my_bar
类型:
my_bar some_bar;
答案 5 :(得分:0)
其他答案都是正确且有用的,但可能需要更长的答案。这样做:
typedef struct Book Book;
typedef struct Books Books;
typedef struct Author Author;
struct Book {
... as you wish ...
};
struct Author {
... as you wish ...
};
struct Books {
... as you wish ...
};
您可以按任意顺序定义struct
,只要它们只包含指向其他struct
的指针。