2016-06-04 21 views
6

Prendiamo il seguente esempio:Comportamento indefinito con type cast?

typedef struct array_struct { 
    unsigned char* pointer; 
    size_t length; 
} array; 

typedef struct vector_struct { 
    unsigned char* pointer; 
    // Reserved is the amount of allocated memory not being used. 
    // MemoryLength = length + reserved; 
    size_t length, reserved; 
} vector; 


// Example Usage: 
vector* vct = (vector*) calloc(sizeof(vector), 1); 
vct->reserved = 0; 
vct->length = 24; 
vct->pointer = (unsigned char*) calloc(arr->length, 1); 

array* arr = (array*) vct; 
printf("%i", arr->length); 
free(arr->pointer); 
free(arr); 

C sembra allocare memoria per i membri struct nell'ordine che stanno definiti nel struct. Il che significa che se lanci vector -> array otterrai comunque gli stessi risultati se esegui operazioni su array come se lo avessi fatto su vector poiché hanno gli stessi membri e l'ordine dei membri.

Fintanto che è stato eseguito il cast solo da vector -> array come se array fosse un tipo generico per vector, non si dovrebbe incorrere in alcun problema.

È questo comportamento indefinito e cattivo nonostante la struttura simile dei tipi?

+4

Stai assumendo '' array' e VECTOR' hanno la stessa imbottitura, che non credo è garantita. – Cornstalks

+0

Perché non dovrebbero? Il padding non dovrebbe differire se hanno la stessa struttura. Eventuali imbottiture aggiuntive si troverebbero alla fine, al di fuori della struttura, dove non dovrebbe avere importanza. – FatalSleep

+0

Posso capire perché questo potrebbe essere un comportamento irregolare, ma non sicuro al 100% se non è definito e possiede una minaccia reale. – FatalSleep

risposta

6

Questo è un comportamento ben definito, se si consente tipo di aliasing (che C non ma la maggior parte dei compilatori fare, sia per difetto o da qualche bandierina di compilazione), ed è un comportamento indefinito se si vieta questo tipo di tipo aliasing (che viene comunemente definito "aliasing rigoroso" perché le regole sono piuttosto severe). Dal progetto N1570 dello standard C:

6.5.2.3

6 Uno speciale garanzia è fatto in modo da semplificare l'utilizzo dei sindacati: se un'unione contiene diverse strutture che condividono una sequenza iniziale comune (vedi sotto), e se l'oggetto unione contiene attualmente una di queste strutture, è consentito ispezionare la parte iniziale comune di ognuna di esse ovunque sia visibile una dichiarazione del tipo completo dell'unione. Due strutture condividono una sequenza iniziale comune se i membri corrispondenti hanno tipi compatibili (e, per campi bit, le stesse larghezze) per una sequenza di uno o più membri iniziali.

Quella sezione riguarda i sindacati, ma in modo che il comportamento ad essere legale in sindacati, limita le possibilità di imbottitura e richiede le due strutture di condividere un layout comune e imbottitura iniziali in tal modo. Quindi abbiamo questo per noi.

Ora, per la rigorosa aliasing, la norma dice:

6,5

7 Un oggetto deve avere il suo valore memorizzato accessibile solo da un'espressione lvalue che ha uno dei seguenti tipi:

  • un tipo compatibile con il tipo effettivo dell'oggetto
  • [...]

A "tipo compatibile" è:

6.2.7

1 Due tipi hanno tipo compatibile se i loro tipi sono uguali.

Continua a spiegarlo più e elencare alcuni casi che hanno un po 'più "spazio di manovra", ma nessuno di essi si applica qui. Sfortunatamente per te, il dollaro si ferma qui. Questo è un comportamento indefinito.

Ora, una cosa si potrebbe fare per aggirare questo sarebbe:

typedef struct array_struct { 
    unsigned char* pointer; 
    size_t length; 
} array; 

typedef struct vector_struct { 
    array array; 
    size_t reserved; 
} vector; 
+1

Volevo solo pubblicare la stessa citazione, anche se non sono d'accordo sul fatto che possiamo dedurre che ciò che l'OP fa è ben definito. Ma sono d'accordo che dovrebbe funzionare nella pratica. – alain

+0

La carne è qui "* di uno ** o più ***". – alk

+0

Non posso dire che sia ben definito - ma quando compilato in VS funziona come un fascino come ho ipotizzato. Dovrò controllare il GCC. – FatalSleep

Problemi correlati