Union und Struktur Memory Sharing
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
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.
- 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 dasstruct 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.