2012-11-14 4 views
8

Ho trovato un codice implementato come la demo simile mostrato di seguito ..Quali sono i vantaggi delle strutture/unioni senza nome in C?

struct st 
{ 
int a; 
struct 
{ 
int b; 
}; 
}; 

6.58 Unnamed struct/union campi all'interno structs/unions

Come consentito dalla ISO C11.

Ma quali sono i vantaggi?

Poiché comunque posso accedere ai membri di dati in uno stesso modo come

int main() 
{ 
struct st s; 
s.a=11; 
s.b=22; 
return 0; 
} 

compilato su gcc 4.5.2 con,

gcc -Wall demo.c -o demo 

e nessun errore,

+0

possibile duplicato del [Quali sono le strutture anonime e sindacati utili per a C11?] (Http://stackoverflow.com/questions/8932707/what-are-anonymous-structs-and-unions-useful-for-in- c11) –

risposta

14

Non deve essere una struttura anonima all'interno di una struct, che non trovo molto utile: in genere questo cambia solo leggermente il layout introducendo più padding, senza altri effetti visibili (rispetto all'inlining dei membri di la struttura del figlio nella struttura principale).

Penso che il vantaggio di struct/unions anonimi è altrove: possono essere utilizzati per posizionare una struttura anonima all'interno di un'unione o un'unione anonima all'interno di una struttura.

Esempio:

union u 
{ 
    int i; 
    struct { char b1; char b2; char b3; char b4; }; 
}; 
+1

Puoi spiegare come usare questo sindacato? Ad esempio, se ho istanza x di te e uso 'x.b1 = 'a'', il resto b2, b3, b4 sarà inizializzato e occuperà spazio di memoria? – Herbert

+0

@Herbert Uguale a una struttura tradizionale (denominata) all'interno di un'unione. La tua domanda riguarda davvero i sindacati contenenti le strutture. Dovresti chiederlo come domanda SO invece che come commento su una risposta a una domanda più specifica, ma dato che hai fatto quest'ultima, 'x.b1 = 'a'' non inizializza i membri' b2', 'b3' , 'b4' ma questi" occupano spazio di memoria ", come si può vedere stampando il valore di' sizeof (union u) '. In teoria, se si dichiara una variabile 'union u' di cui si usa sempre il membro' b1', un compilatore sufficientemente intelligente può riservare solo memoria per 'b1', ... –

+0

@Herbert ma in linea di principio dichiara un' union u' oggetto significa che potresti voler scrivere su uno qualsiasi dei membri delle strutture che contiene in seguito, quindi la memoria dovrebbe essere riservata a loro. –

11

Il vantaggio è piuttosto ovvio, non è vero? Si risparmia al programmatore di avere un nome! Dal naming things is hard, è bello che sia possibile evitare di farlo se non ce n'è bisogno.

E 'anche un segnale abbastanza chiaro che questo struct è locale e mai usato in qualsiasi altro luogo, ma nel contesto di essere un campo nella struct genitore, che è in realtà, le informazioni veramente bello in quanto riduce la possibilita di accoppiamento inutile .

Pensate ad esso come static; limita la visibilità dell'interno struct a quella esterna, in modo simile (ma non, ovviamente, equivalente a) a come static limita la visibilità dei simboli globali all'unità di compilazione in cui compaiono.

+0

Poco elaborato .. statico ?? e un altro se quello è locale dentro usando lo stesso nome di identificatore dà errore .. ma in funzione possiamo dare lo stesso identificatore di nome dentro {} a causa dell'ambito del blocco perché non è permesso qui struct {} – Omkant

+4

'struct' diventa così locale che è difficile capire perché il programmatore non sta inserendo i suoi membri direttamente nella struttura principale. Questa risposta nella sua versione attuale non elenca alcun vantaggio rispetto a tale alternativa. Il layout è diverso tra la struct annidata rispetto ai membri inline (con più padding, che può essere l'effetto desiderato ma di solito viene considerato uno svantaggio). –

+0

Sembra che un "sindacato" anonimo sia molto più vantaggioso di una struttura anonima, per la ragione sopra riportata. – sherrellbc

1

Ho appena incontrato un enorme vantaggio di anonimi union. Tuttavia, tieni presente che questa non è una storia per i deboli di cuore, né è una pratica consigliata.

In un programma C precedente di centinaia di file di codice sorgente esiste una variabile globale, un struct, che conteneva un struct come membro. Quindi la definizione del tipo per la variabile globale sembrava qualche cosa come:

typedef struct { 
    LONG  lAmount; 
    STRUCTONE largeStruct; // memory area actually used for several different struct objects 
    ULONG  ulFlags; 
} STRUCTCOMMON; 

Il struct, STRUCTONE, è stato uno dei molti grandi struct però gli altri erano tutti più piccoli STRUCTONE al momento questo codice è stato scritto. Quindi questa area di memoria, largeStruct veniva utilizzata come union ma senza le istruzioni di origine appropriate che lo indicano. Invece varie variabili struct sono state copiate in quest'area utilizzando memcpy().A peggiorare le cose a volte ciò avveniva attraverso il nome effettivo della variabile globale e talvolta tramite un puntatore alla variabile globale.

Come accade di solito mentre il tempo procede con le ultime modifiche, una delle altre strutture è diventata la più grande. E mi sono trovato di fronte a dover esaminare un centinaio di file cercando dove fosse usato insieme a tutti i vari alias e tutto il resto.

E poi ho ricordato le unioni anonime. Così ho modificato il typedef essere la seguente:

typedef struct { 
    LONG  lAmount; 
    union { 
     // anonymous union to allow for allocation of largest space needed 
     STRUCTONE largeStruct; // memory area actually used for several different struct objects 
     STRUCTTHREE largerStruct; // memory area for even larger struct 
    }; 
    ULONG  ulFlags; 
} STRUCTCOMMON; 

E poi ricompilato ogni cosa.

Quindi ora tutti quei giorni di revisione del codice sorgente e test di regressione non vedevo l'ora di essere più necessario.

E ora posso iniziare il processo di modifica lentamente della sorgente utilizzando questo globale per portare questa sorgente a standard più moderni sulla mia tabella di orari.