2009-05-20 11 views
28

Qual è il modo migliore per risolvere la seguente dipendenza circolare nel typedef di queste strutture?
Nota il tag linguaggio C - Sto cercando una soluzione in gcc serie C.Risolvi la dipendenza circolare typedef?

typedef struct { 
    char* name; 
    int age; 
    int lefthanded; 
    People* friends; 
} Person; 

typedef struct { 
    int count; 
    int max; 
    Person* data; 
} People; 

risposta

27

Forward-dichiarare uno dei struct:


struct people; 

typedef struct { 
    /* same as before */ 
    struct people* friends; 
} Person; 

typedef struct people { 
    /* same as before */ 
} People; 
+2

Qualcuno dovrebbe dire che si dovrebbe scrivere typedef struct people {....} People; poi. quindi, non è esattamente la stessa di prima (imho, è comunque una buona idea dare anche nomi di tag espliciti) –

+0

Hai ragione, era pigro tornare indietro e modificare la risposta, lo farò ora. –

+1

In struct Person non possiamo dichiarare 'struct people friends' invece di un puntatore ?. Getta errore per me. Ad esempio: 'struct people;' 'typedef struct {struct people friends;} Person;' e 'typedef struct people {Persona person;};' –

1

Dal Person vuole solo un puntatore ad People, dovrebbe andare bene per predichiarare solo quest'ultimo:

typedef struct People People; 

quindi modificare la seconda dichiarazione di dichiarare semplicemente utilizzando il tag struct, in questo modo:

struct People { 
    int count; 
    int max; 
    Person data[]; 
}; 
0
struct People_struct; 

typedef struct { 
    char* name; 
    int age; 
    int lefthanded; 
    struct People_struct* friends; 
} Person; 

typedef struct People_struct { 
    int count; 
    int max; 
    Person data[]; 
} People; 
1
struct _People; 

typedef struct { 
    char* name; 
    int age; 
    int lefthanded; 
    struct _People* friends; 
} Person; 

struct _People { 
    int count; 
    int max; 
    Person data[1]; 
}; 

Nota: è Person data[]; norma?

+0

good catch - Ho aggiornato l'esempio;) –

5

Per quanto riguarda la leggibilità:

typedef struct Foo_ Foo; 
typedef struct Bar_ Bar; 

struct Foo_ { 
    Bar *bar; 
}; 

struct Bar_ { 
    Foo *foo; 
}; 

Potrebbe essere una buona idea per evitare typedef struct del tutto;

35

La risposta sta nella differenza tra dichiarazione e definizione. Stai tentando di dichiarare e definire nello stesso passo (nel caso di un nuovo tipo tramite typedef). È necessario suddividerli in diversi passaggi in modo che il compilatore sappia di cosa si sta parlando in anticipo.

typedef struct Person Person; 
typedef struct People People; 

struct Person { 
    char* name; 
    int age; 
    int lefthanded; 
    People* friends; 
}; 

struct People { 
    int count; 
    int max; 
    Person* data; 
}; 

Nota l'aggiunta dei due typedef 'vuoti' nella parte superiore (dichiarazioni). Questo dice al compilatore che il nuovo tipo Persona è di tipo 'struct Person' in modo che quando vede che all'interno della definizione di struct People sa cosa significa.

Nel tuo caso particolare, potresti effettivamente farla franca solo prevenendo il typdef People perché questo è l'unico tipo utilizzato prima che venga definito. Nel momento in cui entri nella definizione di struct People, hai già completamente definito il tipo Persona. Così il seguente sarebbe anche funzionare, ma è SCONSIGLIATO perché è fragile:

typedef struct People People; 

typedef struct { 
    char* name; 
    int age; 
    int lefthanded; 
    People* friends; 
} Person; 

struct People { 
    int count; 
    int max; 
    Person* data; 
}; 

Se si scambia l'ordine delle definizioni di struttura (in movimento struct persone al di sopra del typedef di persona) fallirà di nuovo. Questo è ciò che rende questo fragile e, quindi, non raccomandato.

Si noti che questo trucco NON funziona se si include una struttura del tipo specificato piuttosto che un puntatore ad esso. Così, per esempio, il seguente NON compilare:

typedef struct Bar Bar; 

struct Foo 
{ 
    Bar bar; 
}; 

struct Bar 
{ 
    int i; 
}; 

Il codice di cui sopra dà un errore di compilazione perché il tipo Bar è incompleta quando si tenta di utilizzare all'interno della definizione di struct Foo. In altre parole, non sa quanto spazio assegnare alla "barra" del membro della struttura perché non ha visto la definizione di struct bar in quel punto.

Questo codice verrà compilato:

typedef struct Foo Foo; 
typedef struct Bar Bar; 
typedef struct FooBar FooBar; 

struct Foo 
{ 
    Bar *bar; 
}; 

struct Bar 
{ 
    Foo *foo; 
}; 

struct FooBar 
{ 
    Foo  foo; 
    Bar  bar; 
    FooBar *foobar; 
}; 

Questo funziona, anche con i puntatori circolari interne Foo e bar, perché 'Foo' il tipo e 'Bar' sono stati pre-dichiarata (ma non ancora definito) in modo che il compilatore possa creare un puntatore.

Nel momento in cui definiamo FooBar, abbiamo definito quanto sono grandi sia Foo sia Bar in modo da poter includere gli oggetti reali. Possiamo anche includere un puntatore autoreferenziale per digitare FooBar perché abbiamo pre-dichiarato il tipo.

Si noti che se si sposta la definizione di struct FooBar sopra le definizioni di struct Foo o Bar, non si compila per lo stesso motivo dell'esempio precedente (tipo incompleto).

+0

Bella risposta. Benvenuto in SO! –

+0

+1 per la bella spiegazione! – Dogbert

Problemi correlati