2010-02-16 6 views
1

GCC me donne un "type tableau a type d'élément incomplet" -erreur message lorsque je tente de compiler ceci:GCC: le type de tableau a un type d'élément incomplet?

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

En mémoire struct devrait ressembler à ceci

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

Répondre

7

C'est parce que l'expression de type C fonctionne dans l'autre sens.

Ce:

node (*children)[2]; 

lit comme suit: le contenu de children, lorsque déréférencé (* est appliqué à eux), donnent quelque chose sur lequel l'opérateur de tableau [] peut être appliqué, ce qui donne un node. Ce qui signifie que children est un pointeur vers un tableau de deux node. Cependant, vous ne voulez pas un pointeur vers un tableau, vous voulez un tableau de deux pointeurs. Pour cela, vous devez mettre les parenthèses ainsi:

node *(children[2]); 

qui se lit alors comme: le contenu de children sont un tableau de deux valeurs; l'application de * sur l'un d'eux donne un node. C'est ce que vous voulez: un tableau de deux pointeurs à node. Notez que cela équivaut à:

node *children[2]; 

parce que dans la syntaxe C, quand il s'agit de taper des expressions, l'opérateur [] a priorité sur l'opérateur *.

Dans votre version initiale, le compilateur C gronde parce qu'au moment où il lit la déclaration, il ne sait pas quelle est la taille node (la définition de la structure n'est pas encore terminée), et, en tant que tel, a du mal à imaginer un type "tableau de deux node". C'est un symptôme plutôt indirect du problème. Remarque: vous ne devez pas utiliser _node ou tout autre identifiant commençant par un trait de soulignement dans votre code. Ces identifiants sont réservés à "l'implémentation". En pratique, les en-têtes du système peuvent les utiliser et les collisions peuvent s'avérer dangereuses. Personnellement, j'ai tendance à ajouter le trait de soulignement au fin, comme ceci: typedef struct node_ node;

+0

Je suis confus pourquoi vous utiliseriez un trait de soulignement du tout. 'typedef struct node node; 'est parfaitement valide et permet d'utiliser' struct node' si jamais vous le désirez. –

+0

@R ..: J'ai rencontré d'anciens compilateurs C où 'typedef struct node node;' n'a pas été accepté. En outre, en C++ (pas C), les espaces de noms pour les balises de structure et les noms de types ne sont pas complètement disjoints; J'ai donc pris l'habitude d'utiliser des identifiants distincts pour les balises de structure et les noms de types, d'où le soulignement final. Je trouve que cela aide aussi mon cerveau: il rend plus évident, pour mes neurones vieillissants, si un identifiant donné est un tag de structure ou un nom typé. –

+0

Je suppose que ces compilateurs manquent également de pointeurs "void". Comme pour C++, un 'struct' crée automatiquement un type, mais les typedefs redondants sont autorisés par le langage, avec' typedef struct foo foo; 'comme un cas particulier très utile. –

2

Au lieu de cela:

node (*children)[2]; 

Utilisez ceci:

struct _node* children[2]; 
+0

Si je remplace "node" par "struct _node" dans la ligne 4 cela ne fonctionne pas. C'est ce que vous voulez dire? – dkreuter

+0

En fait son "noeud * enfants [2];", mais merci. Cela a fonctionné quand j'ai enlevé les parenthèses. ... Des fichus indicateurs! – dkreuter

Questions connexes