2010-05-19 8 views

Antwort

31

Ein union ist kein struct. In einer union belegen alle Daten den gleichen Platz und können über ihre Feldnamen als unterschiedliche Typen behandelt werden. Wenn Sie true zu x.b zuweisen, überschreiben Sie die unteren Bits von 20000.

Genauer gesagt:

20000 binär: 100111000100000

19969 binär: 100111000000001

Was hier geschah, war, dass Sie einen Ein-Byte-Wert von 1 gesetzt (00000001) in den 8 unteren -dem Bits von 200000

Wenn Sie einen struct anstelle eines union, werden Sie Platz haben, sowohl für eine int und bool, anstatt nur ein int, und Sie werden die Ergebnisse sehen, die Sie erwartet haben.

+4

+1: wirklich nette Antwort;) – Simon

3

In einer Union beginnen alle Datenelemente am selben Speicherort. In Ihrem Beispiel können Sie nur jeweils ein Datenelement gleichzeitig verwenden. Diese Funktion kann für einige nette Tricks verwendet werden, jedoch wie die gleichen Daten auf vielfältige Weise ausgesetzt wird:

union Vector3 
{ 
    int v[3]; 
    struct 
    { 
    int x, y, z; 
    }; 
}; 

dem Sie die drei Zahlen entweder nach Name (x, y und z) oder als Array zugreifen können (v).

+5

... oder es * könnte * sowieso. Dann wiederum könnte es Padding zwischen den 'int's in der Struktur einfügen, in welchem ​​Fall' v [1] 'und' v [2] 'NICHT wie beabsichtigt' y' und 'z' entsprechen. –

+0

Mir ist kein Compiler bekannt, der je zwei Datenelemente desselben Typs auffüllen würde. Padding tritt auf, wenn aufeinanderfolgende Datenelemente unterschiedliche Größen haben, wie zum Beispiel ein Zeichen gefolgt von einem kurzen Zeichen (am ehesten würde ein zusätzliches Zeichen zwischen den beiden Zeichen gepackt werden). Das heißt, die Struktur könnte gepolstert werden, so dass ihre Gesamtgröße wortorientiert ist. Wenn also x, y und z jeweils ein Byte wären, wäre es möglich, dass sie als x, y, z, p oder p aufgefüllt würden. x, y, z (was in der Tat mein Beispiel brechen würde). –

+1

Beachten Sie, dass weder C noch C++ anonyme Strukturen haben. Sie müssen also einen Namen wie '} vs;' für das struct-Objekt eingeben. Oder setzen Sie auf Compiler-Erweiterungen, wenn Sie können. –

3

Eine Union speichert nur eine der Mitglieder zu einem bestimmten Zeitpunkt. Um definierte Ergebnisse zu erhalten, können Sie nur das gleiche Mitglied von die Union lesen, die zuletzt bis der Union geschrieben wurde. Sonst gibt es (wie Sie hier sind) offiziell nichts mehr oder weniger als undefinierte Ergebnisse.

Manchmal werden Verbindungen absichtlich für Typ-Punning verwendet (z. B. die Bytes betrachten, aus denen ein Float besteht). In diesem Fall liegt es an Ihnen, zu verstehen, was Sie bekommen. Die Sprache versucht, Ihnen eine Chance zu geben, aber es kann nicht wirklich viel garantieren.

+0

Ich glaube nicht, dass irgendetwas, was Sie hier gesagt haben, tatsächlich falsch ist, aber ich stelle die Verwendung des Wortes "undefined" in Frage. "undefiniert" ist, wenn Sie aus nicht initialisiertem Speicher lesen; Wenn Sie vier Bytes haben und einen davon überschreiben, sollten Sie genau wissen, was Sie haben werden (dachte, es könnte komisch aussehen, wenn Sie es einmal umgesetzt haben). – danben

+0

@danben, Sie wissen nicht einmal, dass Sie ein Byte überschreiben. Das Schreiben mit dem booleschen Wert könnte einen zufälligen Teil des int überschreiben, das später, wenn Sie den int lesen, ohne ihm später zuzuweisen, eine CPU-Ausnahme oder ähnliches verursachen könnte (sowohl C als auch C++ erlauben solche Dinge). Verhalten ist wirklich undefiniert, alles kann passieren. –

+0

Ich glaube nach dem Standard, dass dieses spezielle Verhalten implementierungsdefiniert ist. – danben

1

Union in C erleichtern die gemeinsame Nutzung von Speicherplatz durch verschiedene Variablen.
Wenn Sie also eine Variable innerhalb der Union ändern, werden auch alle anderen Variablenwerte beeinflusst.

Verwandte Themen