2011-10-11 2 views
7

Ho letto che se si dichiara due le strutture come questa:Questo codice è garantito dallo standard C?

struct Node { 
    int a, b, c; 
}; 

struct DerivedNode { 
    struct Node base; 
    int d, e, f; 
}; 

Quindi è possibile utilizzare i puntatori a loro in questo modo:

struct DerivedNode myDerivedNode; 
struct Node *regularNode = (struct Node *) &myDerivedNode; 

regularNode->a = 3; 

In altre parole, gli offset di indirizzo per a, b, c sono gli stessi entro struct Node e struct DerivedNode. In questo modo è possibile ottenere una sorta di polimorfismo, in cui è possibile passare in modo forzato il puntatore DerivedNode (struct Node *) ovunque venga normalmente utilizzato un puntatore del nodo.

La mia domanda è se questo comportamento è garantito. So che ci sono alcuni strani problemi di allineamento della memoria e che il compilatore a volte riordina i campi per ottenere un migliore riempimento in memoria. Il campo base si troverà mai in un punto qualsiasi ma all'inizio di struct DerivedNode?

+0

Hai dimenticato la parola chiave 'struct' in diversi punti, no? –

+0

@Jens Oh sì, probabilmente. Scusa –

risposta

13

Questo è garantito per funzionare dallo standard. Membri a struct sono arredare in sequenza nell'ordine specificato e il primo membro appare sempre all'offset 0.

estratti rilevanti dallo standard ANSI C:

Una struttura è un tipo costituito da una sequenza di membri, la cui memoria è allocata in una sequenza ordinata.

Questo afferma che i membri sono disposti in sequenza.

Potrebbe esserci un padding senza nome all'interno di un oggetto struttura, ma non all'inizio.

i mezzi che il primo membro è posizionato all'offset 0.

Nota: estratti standard prese dalla sezione 6.7.2.1 della norma ISO/IEC 9899: TC3 settembre 2007 bozza.

3

Come afferma David, questo è garantito finchè base rimane il primo elemento in DerivedNode.

Ma generalmente questa è una cattiva pratica. Io non riesco a capire molto circostanze in cui non si può dire

struct Node *regularNode = &myDerivNode.base; 

che è l'errore molto più chiara e meno incline nel caso in cui si modificano le strutture in seguito.

+0

+1 Sono d'accordo completamente con questo. –

+0

La circostanza è che sono in una classe di strutture dati in cui sono intrappolato nel 1975 bumming un singolo ramo da (attendere per ..) la ricerca binaria. : P –

1

Questo non risponderà alla tua domanda, ma uno che si preoccupa di scrivere standard ANSI (ISO) C potrebbe compilare il suo codice con gcc -pedantic o -pedantic-errors. Queste opzioni dovrebbero sollevare avvisi/errori di compilazione su righe di codice non standard.

Nota che questo non è efficace al 100%, dal man gcc:

[-pedantic] trova alcune pratiche non ISO, ma non tutti --- solo quelli per i quali ISO C richiede un diagnostica e alcuni altri per i quali è stata aggiunta la diagnostica .