如所写:
typedef struct Foo Foo;
typedef struct Bar Bar;
struct Foo { Bar barOne; Bar barTwo; };
struct Bar { int age, int height };
// Elsewhere, in some function:
Bar barOne = { 2, 4 };
Bar barTwo = { 6, 8 };
Foo instance = { barOne, barTwo };
代码应该无法在任何地方编译(特别是在带有 GCC 4.6.0 的 MacOS X 10.7.1 上失败)并出现以下错误(以及其他一些错误):
xx.c:4: error: field ‘barOne’ has incomplete type
xx.c:4: error: field ‘barTwo’ has incomplete type
Bar
这是因为您在定义之前尝试使用它。反转结构定义的顺序,修复 Bar 中的语法错误(逗号应该是分号;缺少分号),然后(最终)它在 MacOS X 上编译。
标准对使用结构作为初始化器有何规定?
§6.7.8 初始化
¶13 具有自动存储持续时间的结构或联合对象的初始化程序应为如下所述的初始化程序列表,或具有兼容结构或联合类型的单个表达式。在后一种情况下,对象的初始值(包括未命名的成员)是表达式的初始值。
考虑一个函数的上下文(这段代码在 GCC set fussy 下编译成功):
typedef struct Foo Foo;
typedef struct Bar Bar;
struct Bar { int age; int height; };
struct Foo { Bar barOne; Bar barTwo; };
void somefunction(void)
{
Bar barOne = { 2, 4 };
Bar barTwo = { 6, 8 };
Foo instance = { barOne, barTwo };
}
从表面上看,在我看来,它barOne
不是barTwo
单一的表达方式。但是,标准继续说:
¶16 否则,具有聚合或联合类型的对象的初始化程序应是元素或命名成员的初始化程序的大括号括起来的列表。
如果聚合必须用大括号括起来,那么这样写就可以了:
Foo instance = { { barOne }, { barTwo } };
不过,GCC 强烈反对这种结构。
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)
/usr/bin/gcc -g -std=c99 -Wall -Wextra -Wmissing-prototypes -c xx.c
xx.c:8: warning: no previous prototype for ‘somefunction’
xx.c: In function ‘somefunction’:
xx.c:11: error: incompatible types in initialization
xx.c:11: warning: missing initializer
xx.c:11: warning: (near initialization for ‘instance.barOne.age’)
xx.c:11: error: incompatible types in initialization
xx.c:11: warning: missing initializer
xx.c:11: warning: (near initialization for ‘instance.barTwo.age’)
xx.c:11: warning: missing initializer
xx.c:11: warning: (near initialization for ‘instance.barOne’)
xx.c:11: warning: unused variable ‘instance’
总的来说,我倾向于相信 GCC 的判断,并指责 LCC 没有有效地处理案件。争论这将需要完整解析 C 标准的第 6.7.8 节,并且我没有提供所有材料(在开始示例之前它转到 ¶23)。