2015-11-02 20 views
5

Sono un po 'confuso su come i byte sono ordinati in un struct.Ordine byte nella struttura

Diciamo che ho il seguente struct:

struct container { 
    int myint; 
    short myshort; 
    long mylong; 
}; 

ora, voglio inizializzare una variabile di tipo struct container proprio come il seguente, se non che io voglio farlo utilizzando un array.

struct container container1 = {.myint = 0x12345678, 
           .myshort = 0xABCD, 
           .mylong = 0x12345678}; 

Assumere sizeofint e long sono 4, e quello di short è 2.

Assumere che non ci sia il riempimento.

Come sarebbe il layout di 10 bytes di struct?

Dipende dalla endianità?

sarebbe che si tratti del tipo:

0x12345678 ABCD 12345678 

o simile:

0x78563412 CDAB 78563412 

Quello che voglio fare è: Ho il seguente array di caratteri:

char buffer[10] = {0}; 

voglio per riempire manualmente questo array con i dati e quindi memcpy per struct.

dovrei fare [1]:

buffer[0] = 0x12345678 & 0xFF; 
buffer[1] = 0x12345678 >> 8 & 0xFF; 
buffer[2] = 0x12345678 >> 16 & 0xFF; 
buffer[3] = 0x12345678 >> 24 & 0xFF; 
... 
buffer[9] = 0x12345678 >> 24 & 0xFF; 

o dovrebbe essere [2]:

buffer[0] = 0x12345678 >> 24 & 0xFF; 
buffer[1] = 0x12345678 >> 16 & 0xFF; 
buffer[2] = 0x12345678 >> 8 & 0xFF; 
buffer[3] = 0x12345678 & 0xFF; 
... 
buffer[9] = 0x12345678 & 0xFF; 

prima che io faccio il mio memcpy come:

memcpy(&container1, buffer, sizeof(container1); 

E, se io sono wr è un array e copia a struct, è portatile su tutti i sistemi, specialmente per quanto riguarda l'endianness?

EDIT: Does [1] lavoro su una macchina endian poco e [2] su un big endian?

+5

No, non è portabile. Sì, dipende da endianness. E le ipotesi sul riempimento e sulla dimensione dei tipi porteranno anche a problemi di portabilità. – user3386109

+0

Per enfatizzare * nessun modo portabile *, ciò significa che nessun modo portabile dal compilatore al compilatore sullo stesso sistema operativo, molto meno portabile dal sistema operativo al sistema operativo. –

+0

Ovviamente dipende da endianness! Dopo la tua ipotesi "non c'è padding" la domanda non ha più nulla a che fare con i tipi di struct. Si tratta semplicemente di rappresentare numeri interi in memoria. – AnT

risposta

2

Dipende dalla endianità?

Sì, dipende dal tipo di macchina. Quindi la tua logica cambierà a seconda della endianità della macchina.

C'è senza senso * farlo a causa di riempimento struttura.Sebbene diversi compilatori forniscano metodi personalizzati per disabilitare il riempimento della struttura. Controllare Force C++ struct to not be byte aligned.

  • È possibile aggiungere un static_assert (richiede il supporto C11) solo per essere sicuri che il codice non viene compilato a meno che lo struct è fitto. Non avrai il codice portatile ma puoi comunque essere sicuro che se il tuo codice verrà compilato, si comporterà correttamente.

    static_assert(sizeof(container) == sizeof(int) + sizeof(short) + sizeof(long)); 
    
+0

I modi in cui i diversi compilatori forniscono il riempimento della struttura disabilitante non sono portabili - ogni compilatore ha il suo, a meno che non ne emuli un altro per la compatibilità. Potrebbe essere necessario notare che 'static_assert' richiede un compilatore C11 (o un'estensione non standard nei compilatori conformi a C99 o C90). –

+0

@JonathanLeffler Ho menzionato che nella mia risposta e le risposte sulla domanda che ho collegato menzionano che la soluzione OP cerca non può essere portabile. Modifica per enfatizzarlo ulteriormente. – bashrc

+2

Ho opinioni miste sul collegamento a una domanda solo C++ in una domanda solo C. È almeno una bandiera di avvertimento. –

1

C'è un altro problema, quello di allineamento elemento all'interno della vostra struct.

La tua struttura ha intervalli per l'allineamento. Il layout reale è come se avete fatto:

struct container { 
    int myint; 
    short myshort; 
    char __pad__[2]; // padding to align mylong to 4/8 byte boundary 
    long mylong; 
}; 

Cosa succede ad usare un union:

union { 
    struct container vals; 
    char buf[10]; 
}; 

Ma, perché vuoi fare questo? Per quasi tutti gli scenari a cui riesco a pensare, probabilmente c'è un modo più pulito per ottenere l'effetto.

Quando dici array, vuoi dire che vorresti iniziare un array delle tue strutture? Questo può essere fatto:

struct container conts[3] = { 
    { .myint = 1, .myshort = 2, .mylong = 3 }, 
    { .myint = 4, .myshort = 5, .mylong = 6 }, 
    { .myint = 7, .myshort = 8, .mylong = 9 } 
}; 

A proposito, non v'è un modo per fare static_assert in C:

// compile time assertion -- if the assertion fails, we will get two case 0:'s 
// which will cause the compiler to flag this 
#define static_assert(_assert) \ 
    do { \ 
     switch (0) { \ 
     case (_assert): \ 
      break; 
     case 0: \ 
      break; \ 
     } \ 
    } while (0) 
+0

Invece di 'char buf [10];', meglio usare 'char buf [sizeof (struct container)];'. – alk

Problemi correlati