所有结构标识符都自动向前声明

Moh*_*ain 12 c struct c99 incomplete-type ansi-c

在回答警告:从链表数组的不兼容指针类型进行赋值时,我注意到任何用struct关键字表示的未声明标识符都被视为前向声明的标识符.

例如,下面程序编译得很好:

/* 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;
}
Run Code Online (Sandbox Code Playgroud)

我的问题:哪条规则指导C编译器将未声明的struct identifiers视为前向声明的不完整struct类型?

pmg*_*pmg 10

标准说(6.2.5.28)

所有指向结构类型的指针都应具有相同的表示和对齐要求.

这意味着编译器知道如何表示任何结构的指针,甚至是那些尚未定义的结构.
你的程序只处理指向这种结构的指针,所以没关系.


250*_*501 7

它在6.2.5类型和6.7.2.3标签中描述.

struct identifier 是一种对象类型.

6.2.5类型

  1. 存储在对象中或由函数返回的值的含义由用于访问它的表达式的类型确定.(声明为对象的标识符是最简单的表达式;类型在标识符的声明中指定.)类型被分区为对象类型(描述对象的类型)和函数类型(描述函数的类型).在翻译单元内的各个点处,对象类型可能是不完整的(缺少足够的信息来确定该类型的对象的大小)或完整的(具有足够的信息).37)

37)在整个翻译单元中,类型可能是不完整的或完整的,或者它可能在翻译单元内的不同点处改变状态.

  1. 未知大小的数组类型是不完整类型.对于该类型的标识符,通过在稍后的声明中指定大小(具有内部或外部链接)来完成. 未知内容的结构或联合类型(如6.7.2.3中所述)是不完整类型.对于该类型的所有声明,通过在稍后的同一范围内声明相同的结构或联合标记及其定义内容,它已完成.

6.7.2.3标签

  1. 具有相同作用域且使用相同标记的结构,联合或枚举类型的所有声明都声明相同的类型.无论是否存在标签或该类型的其他声明在同一翻译单元中,该类型都是不完整的129)直到定义内容的列表的右括号之后,并且此后完成.

129)仅当不需要该类型的对象的大小时,才可以使用不完整类型.例如,当typedef名称声明为结构或联合的说明符,或者声明指向返回结构或联合的函数的指针时,则不需要它.(参见6.2.5中的不完整类型.)在调用或定义此类函数之前,必须完成规范.


Rhi*_*ica 6

除了2501提供的答案,以及您对它的评论" 在我的情况下,甚至没有前瞻性声明 ",以下内容.

任何使用struct tag计数作为结构类型的(前向)声明,如果之前没有声明的话.虽然更正式的方式是说这只是一种类型,因为C标准没有提到"结构类型的前向声明",只是完整和不完整的结构类型(6.2.5p22).

6.7.2类型说明符告诉我们struct-or-union-specifier是一个类型说明符,而6.7.2.1结构和联合说明符第1段告诉我们反过来,struct identifier是一个struct-or-union-specifier.

假设你有一个链表声明,例如

struct node {
    struct node *next;
    int element;
};
Run Code Online (Sandbox Code Playgroud)

那么这种不完整类型的"隐含前向声明"对于这种结构起作用至关重要.毕竟,类型struct node 在终止分号处完成.但是你需要引用它才能声明next指针.

此外,struct node声明(不完整类型)可能超出范围,就像任何其他声明一样.例如,如果你有一些原型,就会发生这种情况

int function(struct unknown *parameter);
Run Code Online (Sandbox Code Playgroud)

其中struct unknown立即在声明的末尾超出范围.任何进一步声明的struct unknowns都与此不同.这在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
Run Code Online (Sandbox Code Playgroud)

你可以通过在它之前添加一个额外的前向声明来解决这个问题,这使得范围开始更早(因此结束更晚):

struct unknown;
int function(struct unknown *parameter);
Run Code Online (Sandbox Code Playgroud)