views:

478

answers:

2

GCC gives me an "array type has incomplete element type"-error message when i try to compile this:

typedef struct _node node;
struct _node{
 int foo;
 node (*children)[2];
 int bar;
};

In memory the struct should look like this

0x345345000000 foo
0x345345000004 pointer to 1. child node
0x345345000008 pointer to 2. child node
0x34534500000C bar
+2  A: 

Instead of this:

 node (*children)[2];

Use this:

 struct _node* children[2];
JSBangs
If I replace "node" by "struct _node" in line 4 it doesn't work.Is that what you mean?
knizz
Actually its "node* children[2];", but thank you. It worked when I removed the brackets. ... Damn pointers!
knizz
+5  A: 

That's because the C type expression works the other way round.

This:

node (*children)[2];

reads as the following: the contents of children, when dereferenced (* is applied to them), yield something on which the array operator [] can be applied, yielding a node. Which means that children is a pointer to an array of two node. However, you do not want a pointer to an array, you want an array of two pointers. For that, you should put the parentheses thus:

node *(children[2]);

which then reads as: the contents of children are an array of two values; applying * on one of them yields a node. This is what you want: an array of two pointers to node. Note that this is equivalent to:

node *children[2];

because in the C syntax, when it comes to type expressions, the [] operator takes precedence over the * operator.

In your initial version, the C compiler grumbles because at the time it reads the declaration, it does not know what size node is (the structure definition is not complete yet), and, as such, has trouble imagining a type "array of two node". This is a rather indirect symptom of the problem.

Side note: you should refrain from using _node or any other identifier beginning with an underscore in your code. These identifiers are reserved for "the implementation". In practice, system headers may use them, and collisions could prove harmful. Personally, I tend to add the underscore at the end, like this: typedef struct node_ node;

Thomas Pornin
I'm confused why you'd use an underscore at all. `typedef struct node node;` is perfectly valid and makes it possible to use `struct node` if you ever want/need to.
R..
@R..: I have encountered old C compilers where `typedef struct node node;` was not accepted. Also, in C++ (not C), the namespaces for structure tags and type names are not fully disjoint; so I took the habit to use distinct identifiers for structure tags and type names, hence the final underscore. I find that it also helps my brain: it makes it more obvious, to my aging neurons, whether a given identifier is a structure tag or a typedef-ed name.
Thomas Pornin
@Thomas: I'm guessing those compilers also lack `void` pointers. As for C++, a `struct` automatically creates a type, but redundant typedefs are permitted by the language, with `typedef struct foo foo;` as a special case that's very useful.
R..