2013-07-18 75 views
20

正如标题所说,我有这样的代码:C:typedef struct name {...}; VS typedef struct {...}名称;

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; 
}; 

我得到这些错误来自海湾合作委员会:

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 struct{ 
    char firstName[56]; 
    char lastName[56]; 
} Author; 

然后没有警告并没有发生错误。通过搜索通过http://www.amazon.com/C-Programming-Language-2nd-Edition/dp/0131103628和几个小时的谷歌搜索我不明白为什么第一个实施将无法正常工作。

+7

在'Book'之前移动'Author'。还要注意你的'typedef'是多余的 – SomeWittyUsername

+0

在'Author'结构中改变'error:unknown type name'Book''怎么可能呢?请看看[这里](http://msdn.microsoft.com/en-us/library/4x7sfztk%28v=vs.80%29.aspx),它清楚地提到了typdef结构和定义结构之间的区别。 –

回答

46

这里有几件事情正在进行。首先,正如其他人所说,编译器对未知类型的抱怨可能是因为在使用它之前需要定义类型。更重要的是理解3件事的语法:(1)结构定义,(2)结构声明和(3)typedef。当定义一个结构体时,结构体可以被命名,或者未命名(如果没有命名,那么它必须被立即使用(这将解释下面的含义))。

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语言编程,这是与结构特别有用,因为它可以让你声明该类型和治疗结构的名字只是作为自己的一个类型的变量何时离开过这个词“结构”的能力(我们做在C++)。下面是第一定义结构,然后该类型定义结构的一个示例:

struct Name { 
    ... 
}; 

typedef struct Name Name_t; 

在上述OldTypeName是struct Name和NewTypeName是Name_t。所以,现在,申报类型结构名称的变量,而不是写:

struct Name myNameStruct; 

我可以简单的写:

Name_t myNameStruct; 

还要注意,typedef的可与结构定义相结合,这是你在做你的代码是什么:

typedef struct { 
    ... 
} Name_t; 

这也可以被同时命名结构完成,但这是多余的:

typedef struct Name { 
    ... 
} Name_t; 

注意哦:在上面的语法,因为你已经开始用“的typedef”,那么整个语句是一个typedef声明,其中OldTypeName恰好是一个结构定义。因此编译器把右花括号}作为NewTypeName后即将的名字......这是变量名(因为这将是没有类型定义的语法,在这种情况下,你会被定义和结构声明同时结构体变量)。

此外,如果你的状态类型定义,但在随后结束后离开关Name_t,那么你已经有效地创建了一个INCOMPLETE 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不是被保留,也没有被专门分析,也没有被编译器注意到,它仅仅是一个很好的遵循的惯例当你在C中定义新的类型时(通过typedef)。在C++中,很多人使用约定来启动大写的类型名,例如MyNewType(与C约定my_new_type_t相反)。 HTH

+0

我们可以用'_t'后缀声明任何类型吗?我认为这个后缀是C99保留。我错了吗? – nowox

+2

很好的答案,谢谢! – awalllllll

+1

重要的是要注意,自引用结构需要结构体的名称或前向声明的typedef。例如,如果我想要一个类型化的LinkedList节点来写:'typedef struct node_t {void * data; struct node_t next; }节点;'这样的声明是完整和简洁的。 – AaronCarson

0

您只需在定义Book之前定义Author。

您可以在Book中使用Author,因此需要在之前进行定义。

+0

感谢您的快速回复。定义作者之前的书没有错误,在Kernighan和Ritchie的书中检查过。 –

+0

我错了,显然如果我改变立场,它会消除错误。我必须多学习一点。 (对不起,双注释,在计算器中的第一个计时器:P) –

5

语法的typedef情况如下:

typedef old_type new_type 

在你的第一次尝试,你所定义的struct Book类型和Book。换句话说,你的数据类型被称为struct Book而不是Book

在第二种形式中,您使用了typedef的正确语法,因此编译器会识别出名为Book的类型。

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结构,因此对于编译器来说“读取”没有任何用处。

既然你已经知道了答案应该是这种形式

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

坚持这一点。