2012-11-09 26 views
6

Sto leggendo 'The C Programming Language' e ho riscontrato un problema relativo al typedef della struct. Il codice è simile a questo:Declaration rule in struct typedef

typedef struct tnode *Treeptr; 
typedef struct tnode { /* the tree node: */ 
    char *word; /* points to the text */ 
    int count; /* number of occurrences */ 
    struct tnode *left; /* left child */ 
    struct tnode *right; /* right child */ 
} Treenode; 

Per il momento in cui scriviamo

typedef struct tnode *Treeptr; 

tnode non è ancora ancora dichiarato, ma non c'è niente di errore di compilazione, ma quando si cambia la dichiarazione di cui sopra in:

typedef Treenode *Treeptr; 

otteniamo errore di compilazione:

error: parse error before '*' token 
warning: data definition has no type or storage class 

Che cosa fa la differenza? "Struct tnode" non è lo stesso di "Treenode"?

+0

È possibile trovare [Quale parte dello standard C consente la compilazione di questo codice?] (Http://stackoverflow.com/questions/12200096/which-part-of-the-c-standard-allows-this-code -compile) e [Lo standard C considera che ci sono uno o due tipi 'struct uperms_entry' in questa intestazione?] (http://stackoverflow.com/questions/11697705/does-the-c-standard-consider -that-there-are-one-or-two-struct-uperms-entry-typ) come rilevanti, ma possono essere lanciati ad un livello che va oltre quello in cui ti trovi. –

risposta

6

Non è possibile utilizzare un tipo prima che sia definito.

Con la dichiarazione typedef struct tnode { ... } Treenode;, il tipo Treenode non è definito fino a quando non viene raggiunto il punto e virgola.

La situazione con typedef struct tnode *Treeptr; è diversa. Questo dice al compilatore 'c'è un tipo di struttura chiamato struct tnode, e il tipo Treeptr è un alias per un puntatore a un struct tnode'. Alla fine di tale dichiarazione, struct tnode è un tipo incompleto. È possibile creare puntatori a tipi incompleti ma non è possibile creare variabili del tipo incompleto (quindi è possibile definire Treeptr ptr1; o struct tnode *ptr2; e sono dello stesso tipo, ma non è possibile definire struct tnode node;).

Il corpo del struct tnode potrebbe essere scritta come:

typedef struct tnode 
{ 
    char *word; 
    int  count; 
    Treeptr left; 
    Treeptr right; 
} Treenode; 

perché Treeptr è un alias noto per il tipo struct tnode * prima che la struttura è definita. Non è possibile utilizzare Treenode *left; perché Treenode non è un alias noto fino a quando non viene raggiunto il punto e virgola finale (in parole povere).

0

Una riga typedef struct tnode *Treeptr; ha una dichiarazione implicita in avanti della struttura "tnode". E 'simile a:

typedef struct tnode Treenode; 
typedef Treenode *Treeptr; 

struct tnode { /* the tree node: */ 
    char *word; /* points to the text */ 
    int count; /* number of occurrences */ 
    struct tnode *left; /* left child */ 
    struct tnode *right; /* right child */ 
}; 
1

Quando si dichiara TreePtr, non si sta implementando la struct. Questa è nota come "forward declaration". Qualcosa come: "qui usiamo questo, ma più tardi lo spiegherò meglio". L'implementazione deve apparire in un secondo momento, solo una volta, ed è quello che trovi nel secondo typedef.

E TreePtr non è la stessa della struttura, perché TreePtr sarà in realtà un nuovo tipo che include il fatto di essere un puntatore.

+0

Grazie, Felix, bella spiegazione. Quindi intendi 'struct undefined_struct * a;' è permesso, ma dovremmo implementare 'undefined_struct' prima di dire' struct undefined_struct b ', giusto? Ma qual è l'intenzione per questa "dichiarazione _foward_"? – Rain

+1

Dichiarazioni di inoltro, o tipi incompleti, può essere utile in due casi: è possibile creare strutture reciprocamente ricorsive, in modo che 'struct a' contenga un puntatore a' struct b' e 'struct b' contenga un puntatore a' struct a'. Questo è esoterico (ma sarebbe un vero problema se la dichiarazione diretta non fosse possibile). Il motivo più consistente per i tipi incompleti è che è possibile definire l'interfaccia per un insieme di funzioni in termini di puntatori a tipi incompleti e l'intestazione pubblica non deve mai rivelare cosa c'è dentro le strutture, sono un "tipo opaco" e si sta usando il nascondiglio delle informazioni –

+0

Si possono fare cose come 'struct undef a;', 'struct undef * b;', ecc. in qualsiasi combinazione, come tanto quanto è necessario e loro dentro un'altra struttura. Ma tu _devi_ dichiarare l'implementazione della struttura una volta, dove e quando preferisci. –