2015-11-02 20 views
5

Ich bin ein wenig verwirrt darüber, wie Bytes in einem struct geordnet sind.Reihenfolge der Bytes in Struct

Sagen wir, ich habe folgende Struktur:

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

Nun, ich möchte eine Variable vom Typ initialisieren struct container ebenso wie die folgenden, mit der Ausnahme, dass ich wollen tun es mit einem Array.

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

Angenommen sizeofint und long4 sind und dass der short2 ist.

Angenommen, es gibt keine Polsterung. Wie wäre dann das Layout der 10 bytesstruct?

Kommt es auf die Endianness an?

Wäre es wie:

0x12345678 ABCD 12345678 

oder wie:

0x78563412 CDAB 78563412 

Was ich tun möchte, ist: Ich habe folgendes char-Array:

char buffer[10] = {0}; 

Ich möchte um dieses Array manuell mit Daten zu füllen und dann memcpy an die struct.

Sollte ich tun [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; 

oder sollte es sein [2]:

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

, bevor ich meine tun memcpy wie:

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

Und wenn ich wr bin iting zu einem Array und kopieren zu struct, Ist es über Systeme, besonders in Bezug auf endianness portabel?

EDIT: Does [1] Arbeit an einer Little-Endian-Maschine und [2] auf einem Big-Endian?

+5

Nein, es ist nicht tragbar. Ja, es kommt auf Endianness an. Und die Annahmen über Padding und die Größe der Typen werden auch zu Portabilitätsproblemen führen. – user3386109

+0

Um * keine portable Möglichkeit * zu betonen, bedeutet das keine portable Möglichkeit vom Compiler zum Compiler auf dem gleichen Betriebssystem, viel weniger portabel von OS zu OS. –

+0

Natürlich hängt es von Endianness ab! Nach Ihrer Annahme "es gibt keine Auffüllung" hat die Frage nichts mehr mit Strukturtypen zu tun. Es geht einfach darum, ganze Zahlen im Speicher darzustellen. – AnT

Antwort

2

Kommt es auf die Endianness an?

Ja, es hängt von der Endianness der Maschine ab. Ihre Logik wird sich also je nach Endlichkeit der Maschine ändern.

Es gibt keine tragbare Weise *, um es wegen der Strukturauffüllung zu tun.Obwohl verschiedene Compiler benutzerdefinierte Möglichkeiten zum Deaktivieren von Strukturauffüllung bieten. Überprüfen Sie Force C++ struct to not be byte aligned.

  • Sie hinzufügen können, ein static_assert (Unterstützung C11) nur um sicher zu sein, dass Ihr Code kompiliert nicht, wenn Ihre Struktur dicht gepackt ist. Sie werden keinen portablen Code haben, aber Sie können sicher sein, dass sich Ihr Code korrekt verhält, wenn er kompiliert wird.

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

Die Möglichkeiten, die verschiedene Compiler zum Deaktivieren der Strukturauffüllung bieten, sind nicht übertragbar - jeder Compiler hat seinen eigenen, es sei denn, er emuliert einen anderen aus Kompatibilitätsgründen. Sie müssen möglicherweise beachten, dass 'static_assert' einen C11-Compiler (oder eine nicht standardmäßige Erweiterung in Compilern, die C99 oder C90 entsprechen) erfordert. –

+0

@ JonathanLeffler Ich habe erwähnt, dass in meiner Antwort sowie die Antworten auf die Frage, die ich verlinkt erwähnen, dass die Lösung OP sucht nicht tragbar sein kann. Bearbeiten, um es noch weiter zu betonen. – bashrc

+2

Ich habe gemischte Ansichten über die Verknüpfung zu einer C++ - only Frage in einer Nur-C-Frage. Es ist zumindest eine Warnflagge. –

1

Es gibt ein weiteres Problem, dass der Element Ausrichtung innerhalb Ihrer Struktur.

Ihre Struktur hat Lücken für die Ausrichtung. Das eigentliche Layout ist, als ob du getan hast:

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

Was ist mit einem union:

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

Aber warum tun Sie dies tun wollen? Für fast jedes denkbare Szenario gibt es wahrscheinlich einen saubereren Weg, um den Effekt zu erzielen.

Wenn Sie sagen Array, meinen Sie, Sie möchten ein Array Ihrer Strukturen init? Dies kann getan werden:

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

BTW, es ist ein Weg static_assert in C zu tun:

// 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

Anstelle von 'char buf [10];', besser verwenden Sie 'char buf [sizeof (struct container)];'. – alk

Verwandte Themen