在回答warning: assignment from incompatible pointer type for linklist array时,我发现任何使用struct
关键字的未声明标识符都被视为前向声明的标识符。
例如,program below编译良好:
/* Compile with "gcc -std=c99 -W -Wall -O2 -pedantic %" */
#include <stdio.h>
struct foo
{
struct bar *next; /* Linked list */
};
int main(void) {
struct bar *a = 0;
struct baz *b = 0;
struct foo c = {0};
printf("bar -> %p\n", (void *)a);
printf("baz -> %p\n", (void *)b);
printf("foo -> %p, %zu\n", (void *)&c, sizeof c); /* Remove %zu if compiling with -ansi flag */
return 0;
}
我的问题:哪条规则指导C
编译器将未声明的struct identifier
视为前向声明的不完整struct
类型?
答案 0 :(得分:10)
答案 1 :(得分:7)
在6.2.5类型和6.7.2.3标签中描述。
struct identifier
是一种对象类型。
6.2.5类型
- 存储在对象中或由函数返回的值的含义由 用于访问它的表达式的类型。 (声明为对象的标识符是 最简单的表达;类型在标识符的声明中指定。)类型 被分为对象类型(描述对象的类型)和函数类型(类型 描述功能)。 在翻译单元内的各个点处,对象类型可以是 不完整(缺乏足够的信息来确定该类型物体的大小)或 完成(有足够的信息)。 37)
醇>37)整个翻译单元中的类型可能不完整或完整,或者可能会改变状态 翻译单元内的不同点。
- 未知大小的数组类型是不完整类型。它已完成,标识符为 该类型,通过在后面的声明中指定大小(具有内部或外部链接)。 未知内容的结构或联合类型(如6.7.2.3中所述)是不完整类型。对于该类型的所有声明,通过声明相同的结构或完成来完成 union标记及其定义内容稍后在同一范围内。
醇>
6.7.2.3标签
- 具有相同范围和结构的结构,联合或枚举类型的所有声明 使用相同的标签声明相同的类型。无论是否有标签或什么 该类型的其他声明属于同一个翻译单元,类型不完整129) 直到定义内容的列表的右括号后立即完成 此后。
醇>129)只有在不需要该类型对象的大小时才能使用不完整类型。它不是 例如,当typedef名称被声明为结构或联合的说明符时,或者 当声明返回结构或联合的指针或函数时。(参见不完整的类型 在6.2.5中。)在调用或定义这样的函数之前,必须完成规范。
答案 2 :(得分:6)
除了2501提供的答案,以及您对它的评论“在我的情况下,甚至没有前瞻性声明”,以下内容。
任何使用struct tag
都算作结构类型的(前向)声明,如果之前没有声明的话。虽然更正式的方式是说这只是一种类型,因为C标准没有提到“结构类型的前向声明”,只需完成和incomplete structure types (6.2.5p22)。
6.7.2 Type specifiers告诉我们 struct-or-union-specifier 是类型说明符,6.7.2.1 Structure and union specifiers paragraph 1告诉我们转 struct 标识符是 struct-or-union-specifier 。
假设您有一个链接列表声明,例如
struct node {
struct node *next;
int element;
};
然后,这种不完整类型的“隐含前向声明”对于这种结构起作用至关重要。毕竟,在终止分号处输入struct node
is only complete类型。但是你需要引用它才能声明next
指针。
此外,struct node
声明(不完整类型)可能超出范围,就像任何其他声明一样。例如,如果您有一些原型
int function(struct unknown *parameter);
其中struct unknown
在声明结束时立即超出范围。任何进一步声明的struct unknown
都与此不同。 6.2.5p22:
未知内容的结构或联合类型(如6.7.2.3中所述) 是一种不完整的类型。对于所有声明,它已完成 通过声明相同的结构或联合标记及其定义来输入类型 以后的内容在同一范围内。
这就是为什么gcc警告这个:
foo.c:1:21: warning: 'struct unknown' declared inside parameter list
foo.c:1:21: warning: its scope is only this definition or declaration, which is probably not what you want
你可以通过在它之前添加一个额外的前向声明来解决这个问题,这会使范围更早开始(因此会在之后结束):
struct unknown;
int function(struct unknown *parameter);
答案 3 :(得分:2)
我认为使用不完整结构类型的最优雅的用例是这样的:
struct foo
{
struct bar *left;
struct bar *right;
};
struct bar
{
int something;
struct foo *next;
};
即。双递归,其中b和b指向a。 此类情况可能是此功能包含在原始C语言规范中的原因。
最初的问题是是否所有结构标识符都自动转发。我认为最好说所有不完整的结构定义都被自动视为前向声明。
编辑:关于文档的评论,让我们看看C语言圣经:Kerninghan&amp; Ritchie - C编程语言,“6.5自引用结构”部分说:
偶尔,人们需要一种自我参照结构的变体: 两个相互引用的结构。处理这个问题的方法是:
struct t { ... struct s *p; /* p points to an s */ }; struct s { ... struct t *q; /* q points to a t */ };
我同意,有可能以另一种方式实现,但我认为这是C语言作者的良好动机,我同意他们这是实现这一点的优雅方式。