2010-11-16 15 views
14

Wenn ich erklären eine Union:Woher weiß man, welche Variable aus Union verwendet wird?

union TestUnion 
{ 
    struct 
    { 
     unsigned int Num; 
     unsigned char Name[5]; 
    }TestStruct; 
    unsigned char Total[7]; 
}; 

Nun, wie kann ich wissen, dass, ob Summe [7] verwendet wird oder TestStruct verwendet wird?

Ich benutze C! Ich besuchte Gewerkschaften und Strukturen und diese Frage kam mir in den Sinn. "sizeof" kann nicht verwendet werden, da beide von gleicher Größe sind, d.h. 7 Bytes. (Und hier kommt eine andere Frage)

Wenn ich nur "Total" mit einem Zeichen "a" und versuchte sizeof(TestUnionInstance), gab es 12 zurück (Größe von Char ist 1 Byte, oder?). Also habe ich die Struktur isoliert und festgestellt, dass die Größe der Struktur 12 Byte und nicht 5 + 2 = 7 Byte beträgt. Seltsam !! Jeder kann das erklären ??

P.S. Ich verwende Visual Studio 2008.

Antwort

20

Sie können nicht. Das ist Teil der Sache der Gewerkschaften.

Wenn Sie in der Lage sein müssen, zu sagen, können Sie eine so genannte getaggte Union verwenden. Einige Sprachen haben eine integrierte Unterstützung für diese, aber in C müssen Sie es selbst tun. Die Idee besteht darin, ein Tag zusammen mit der Union einzufügen, mit dem Sie feststellen können, um welche Version es sich handelt. Wie:

enum TestUnionTag {NUM_NAME, TOTAL}; 

struct { 
    enum TestUnionTag tag; 
    union { 
     struct { 
      unsigned int Num; 
      unsigned char Name[5]; 
     } TestStruct; 
     unsigned char Total[7]; 
    } value; 
} TestUnion; 

Dann in Ihrem Code, stellen Sie sicher, dass Sie immer das Tag zu sagen, wie die Union verwendet wird.

Über die Größe von: die Struktur ist 12 Bytes, weil es 4 Bytes für die Int (die meisten modernen Compiler haben eine 4-Byte-Int, die gleiche wie eine lange int), dann drei Bytes Padding und fünf Bytes für die Zeichen (ich weiß nicht, ob das Padding vor oder nach den Zeichen kommt). Die Auffüllung ist da, so dass die Struktur eine ganze Anzahl von Wörtern lang ist, so dass alles im Speicher auf Wortgrenzen ausgerichtet bleibt. Da die Struktur 12 Byte lang ist, muss die Union 12 Byte lang sein, um sie zu halten. Die Gewerkschaft ändert nicht die Größe, je nachdem, was darin ist.

+0

ein besonderer Dank für "Padding Part" .... Ich wusste das nicht !! Groß!! – Swanand

+2

Das Padding kommt nach dem 'char', nicht vorher. Streng genommen könnte eine Implementierung * Padding davor setzen, aber dann müsste sie auch die gleiche Menge Padding davor setzen, wenn man von 'char [5]' nach 'char [6]' wechselt, was ziemlich unsinnig wäre . C erfordert Strukturen mit einer gemeinsamen anfänglichen Sequenz von Elementen, die kompatibel sind. –

1

Es gibt keine Möglichkeit zu sagen. Sie sollten einige zusätzliche Flags (oder andere Mittel außerhalb Ihrer Union) haben, die sagen, welcher der Union-Teile wirklich verwendet wird.

6

Das Element zu verwenden ist, die Sie zuletzt schrieb; die anderen (s) sind tabu. Du weißt, an welches Mitglied du zuletzt geschrieben hast, oder? Schließlich ist es ihr war, die das Programm :-)


Was Sie sekundäre Frage geschrieben: der Compiler erlaubt ‚Paddingbytes‘ in der Struktur einzufügen auf nicht ausgerichtete Zugriffe zu vermeiden und machen es performant .

example of a possible distribution of bytes inside your structure 

Num |Name  |pad 
- - - -|- - - - -|x x x 
0 1 2 3|4 5 6 7 8|9 a b 
+1

+1 für die Zeit, um das Speicherlayout des Objekts anzuzeigen. –

+1

Eigentlich müssen Sie manchmal nur auf die anderen Mitglieder zugreifen. Eine wichtige Funktion von Gewerkschaften besteht darin, für dieselben Daten unterschiedliche Ansichten bereitzustellen. – thkala

+1

Was den "off-limits" -Kommentar angeht, ist zu beachten, dass für den Compiler nichts tabu ist. Der Programmierer muss solche Richtlinien manuell erzwingen. – thkala

2

Zuerst sizeof(int) auf den meisten heutzutage Architekturen gehen 4. sein, wenn Sie 2 wollen Sie bei short oder int16_t im stdint.h Header in C99 aussehen sollen, wenn Sie bestimmt sein willst.

Zweitens verwendet C Füllbytes jedes struct, um sicherzustellen, auf eine Wortgrenze ausgerichtet ist (4). So sieht Ihre Struktur wie folgt aus:

+---+---+---+---+---+---+---+---+---+---+---+---+ 
|  Num  | N a m e | | | | 
+---+---+---+---+---+---+---+---+---+---+---+---+ 

Es gibt 3 Bytes am Ende.Andernfalls würde der nächste struct in einem Array sein Num-Feld an einem unpassend ausgerichteten Ort haben, was es weniger effizient machen würde, darauf zuzugreifen.

Drittens ist die sizeof eine Union wird die sizeof sein größtes Mitglied sein. Selbst wenn der gesamte Speicherplatz nicht verwendet wird, gibt sizeof das größte Ergebnis zurück.

Sie müssen, wie andere Antworten erwähnt haben, einen anderen Weg (wie eine enum), um zu bestimmen, welches Feld Ihrer Union verwendet wird.

4

Kurze Antwort: Es gibt keinen Weg, außer durch Hinzufügen einer enum irgendwo in Ihrer Struktur außerhalb der Union.

enum TestUnionPart 
{ 
    TUP_STRUCT, 
    TUP_TOTAL 
}; 

struct TestUnionStruct 
{ 
    enum TestUnionPart Part; 
    union 
    { 
    struct 
    { 
     unsigned int Num; 
     unsigned char Name[5]; 
    } TestStruct; 
    unsigned char Total[7]; 
    } TestUnion; 
}; 

Jetzt werden Sie die Erstellung Ihrer Vereinigung zu steuern, müssen die Enumeration, um sicherzustellen, richtig eingestellt ist, beispielsweise mit Funktionen ähnlich:

void init_with_struct(struct TestUnionStruct* tus, struct TestStruct const * ts) 
{ 
    tus->Part = TUP_STRUCT; 
    memcpy(&tus->TestUnion.TestStruct, ts, sizeof(*ts)); 
} 

Botschaft über die richtigen Werte ist jetzt eine einzige Schalter:

void print(struct TestUnionStruct const * tus) 
{ 
    switch (tus->Part) 
    { 
    case TUP_STRUCT: 
     printf("Num = %u, Name = %s\n", 
      tus->TestUnion.TestStruct.Num, 
      tus->TestUnion.TestStruct.Name); 
     break; 
    case TUP_TOTAL: 
     printf("Total = %s\n", tus->TestUnion.Total); 
     break; 
    default: 
     /* Compiler can't make sure you'll never reach this case */ 
     assert(0); 
    } 
} 

Als Randbemerkung, würde ich erwähnen, dass diese Konstrukte beste Griffe sind d in Sprachen der ML-Familie.

type test_struct = { num: int; name: string } 
type test_union = Struct of test_struct | Total of string 
Verwandte Themen