Union und Struktur Memory Sharing

Nov 05 2020

Ich habe versucht, die Antwort auf eine Frage zu finden, die zwei Strukturen innerhalb einer Gewerkschaft umfasst.

Ich habe die Frage im Online-Debugger eingegeben, die Antwort, die ich finde, und die eigentliche Antwort ist, sich nicht gegenseitig die Hände zu geben. Kann mir jemand mit der Antwort mit Erklärung helfen.

#include <stdio.h>

int main()
{
    union{
            struct{
                       char c[2];
                       char ch[2];
                  }s;
           struct {
                       short int i;
                       short int j;
                 }st;
       }u={12,1,15,1};

  printf("%d%d",u.st.i,u.st.j);
}

Antwort ist 268und271

Antworten

1 0___________ Nov 05 2020 at 18:44

Dezimalzahlen sind für diese Art von Tests nicht sehr gut. Sie sollten auch alle Warnungen aktivieren. Wenn Sie dies tun, werden Sie bekommen

<source>:25:8: warning: missing braces around initializer [-Wmissing-braces]

Schreiben wir also Ihr Programm ein wenig um:

int main()
{
    union
    {
        struct
        {
            char c[2];
            char ch[2];
        }s;
        struct 
        {
            short int i;
            short int j;
        }st;
    }u={.s = {{0x12,0x01},{0x15,0x01}}};  //better to show compiler what you want to initialize

  printf("%04hx %04hx",u.st.i,u.st.j);
}

Und das Ergebnis ist:

0112 0115

Die Zahlen, die wir bei der Initialisierung verwendet haben, werden deutlich angezeigt. Die Zahlen zeigen uns, dass dieses System ein Little-Endian-System verwendet, bei dem das niedrigstwertige Byte an erster Stelle steht.

Sie sollten sich darüber im Klaren sein, dass der Compiler frei ist, die erforderlichen Auffüllungen hinzuzufügen. Um dies zu vermeiden, müssen Sie Compiler-Erweiterungen verwenden - Strukturpackung.

1 Lundin Nov 05 2020 at 18:38
  • Beginnen Sie damit, dies sinnvoller zu machen, indem Sie auf hexadezimal wechseln : {0xC,0x1,0xF,0x1}. Auf diese Weise können wir die Bytes so anzeigen, wie sie im Speicher gespeichert sind, ohne uns Gedanken über die Konvertierung in / von der Dezimalbasis machen zu müssen.
  • Bei der Initialisierung von a unionwird das erste Mitglied initialisiert, in diesem Fall das struct s.
  • Es wäre sauberer zu schreiben, { {{0xC,0x1}, {0xF,0x1}} }aber leider erlaubt C das Weglassen der geschweiften Klammern innerer Strukturen / Arrays, so dass wir schlampig geschriebenen Mist in unsere Initialisierungslisten aufnehmen können, nur weil wir können.
  • Die Speicherreihenfolge eines charByte-Arrays ist auf jedem System immer von oben nach unten: erstes Byte bei niedrigstwertiger Adresse. Das heißt : 0xC 0x1 0xF 0x1.
  • Genau genommen kann der Compiler irgendwo zwischen den Struktur- / Gewerkschaftsmitgliedern Strukturauffüllbytes hinzufügen, um Fehlausrichtungen auszugleichen. Kommt in diesem speziellen Fall nicht vor, aber es würde passieren, wenn wir zum Beispiel verwenden char c[3].
  • Wenn Sie diesen Speicherbereich mit Shorts "pun" eingeben, werden sie entsprechend der Endianess gelesen, da short größer als 1 Byte und ein Integer-Typ ist.
  • Auf einer kleinen Endian-CPU würde daher jeder Kurzschluss annehmen, dass 0xC das niedrigstwertige Byte ist, und der erste Kurzschluss endet als 010CHex.

Wenn wir Ihren Code in hexadezimal übersetzen, sollte dies klarer sein:

#include <stdio.h>

int main()
{
    union{
            struct{
                       char c[2];
                       char ch[2];
                  }s;
           struct {
                       short int i;
                       short int j;
                 }st;
       }u={ {{0xC,0x1}, {0xF,0x1}} };

  printf("%.4X\n%.4X",u.st.i,u.st.j);
}

Ausgabe auf Little Endian CPU:

010C

010F

10Ch = 268d und so weiter.