As written:
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 };
the code should fail to compile everywhere (and specifically fails on MacOS X 10.7.1 with GCC 4.6.0) with these errors (plus some others):
xx.c:4: error: field ‘barOne’ has incomplete type
xx.c:4: error: field ‘barTwo’ has incomplete type
This is because you try to use Bar
before it is defined. Reverse the order of the structure definitions, and fix the syntax errors in Bar (comma should be semi-colon; missing semi-colon), and then (finally) it does compile on MacOS X.
What does the standard say about using structures as initializers?
§6.7.8 Initialization
¶13 The initializer for a structure or union object that has automatic storage duration shall be
either an initializer list as described below, or a single expression that has compatible
structure or union type. In the latter case, the initial value of the object, including
unnamed members, is that of the expression.
Consider the context of a function (this code compiles OK with 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 };
}
Superficially, it looks to me like barOne
and barTwo
are not single expressions. However, the standard goes on to say:
¶16 Otherwise, the initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members.
If the aggregates had to be enclosed braces, then writing this would work:
Foo instance = { { barOne }, { barTwo } };
GCC emphatically rejects this construct, though.
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’
On the whole, I'm inclined to trust GCC's judgement and point the finger at LCC not handling a case validly. Disputing that will require a complete parsing of §6.7.8 of the C standard, and I've not provided all the material (it goes to ¶23 before starting on the examples).