Ich habe Gewerkschaften früher bequem benutzt; Heute war ich alarmiert, als ich diesen Beitrag las und erfuhr, dass dieser Code
union ARGB
{
uint32_t colour;
struct componentsTag
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
} components;
} pixel;
pixel.colour = 0xff040201; // ARGB::colour is the active member from now on
// somewhere down the line, without any edit to pixel
if(pixel.components.a) // accessing the non-active member ARGB::components
ist tatsächlich undefiniertes Verhalten, dh das Lesen von einem anderen Gewerkschaftsmitglied als dem, an das kürzlich geschrieben wurde, führt zu undefiniertem Verhalten. Wenn dies nicht die beabsichtigte Verwendung von Gewerkschaften ist, was ist das? Kann jemand es bitte ausführlich erklären?
Aktualisieren:
Ich wollte im Nachhinein ein paar Dinge klären.
- Die Antwort auf die Frage ist für C und C ++ nicht dieselbe. Mein ignorantes jüngeres Ich hat es sowohl als C als auch als C ++ markiert.
- Nachdem ich den Standard von C ++ 11 durchgesehen hatte, konnte ich nicht abschließend sagen, dass der Zugriff auf / die Inspektion eines nicht aktiven Gewerkschaftsmitglieds undefiniert / nicht spezifiziert / implementierungsdefiniert ist. Alles was ich finden konnte war §9.5 / 1:
Wenn eine Standard-Layout-Union mehrere Standard-Layout-Strukturen enthält, die eine gemeinsame Anfangssequenz haben, und wenn ein Objekt dieses Standard-Layout-Union-Typs eine der Standard-Layout-Strukturen enthält, kann die gemeinsame Anfangssequenz einer beliebigen Struktur überprüft werden von Standard-Layout-Strukturelementen. §9.2 / 19: Zwei Standardlayoutstrukturen teilen eine gemeinsame Anfangssequenz, wenn entsprechende Elemente layoutkompatible Typen haben und entweder kein Element ein Bitfeld ist oder beide Bitfelder mit derselben Breite für eine Sequenz von einem oder mehreren Anfangsbuchstaben sind Mitglieder.
- In C (ab C99 TC3 - DR 283 ) ist dies legal ( danke an Pascal Cuoq , der dies angesprochen hat). Der Versuch, dies zu tun , kann jedoch immer noch zu undefiniertem Verhalten führen , wenn der gelesene Wert für den Typ, den er durchliest, ungültig ist (sogenannte "Trap-Darstellung"). Andernfalls wird der gelesene Wert implementierungsdefiniert.
C89 / 90 hat dies unter nicht spezifiziertem Verhalten (Anhang J) herausgestellt, und das Buch von K & R besagt, dass die Implementierung definiert ist. Zitat von K & R:
Dies ist der Zweck einer Union - eine einzelne Variable, die einen von mehreren Typen rechtmäßig enthalten kann. [...] solange die Verwendung konsistent ist: Der abgerufene Typ muss der zuletzt gespeicherte Typ sein. Es liegt in der Verantwortung des Programmierers, zu verfolgen, welcher Typ derzeit in einer Union gespeichert ist. Die Ergebnisse sind implementierungsabhängig, wenn etwas als ein Typ gespeichert und als ein anderer extrahiert wird.
Auszug aus Stroustrups TC ++ PL (Schwerpunkt Mine)
Die Verwendung von Gewerkschaften kann für die Kompatibilität von Daten von wesentlicher Bedeutung sein, [...] die manchmal für die "Typkonvertierung " missbraucht werden .
Vor allem diese Frage (deren Titel seit meiner Anfrage unverändert geblieben ist) wurde mit der Absicht gestellt, den Zweck von Gewerkschaften zu verstehen UND nicht darüber, was der Standard erlaubt. ZB Die Verwendung der Vererbung für die Wiederverwendung von Code ist natürlich nach dem C ++ - Standard zulässig, aber Es war nicht der Zweck oder die ursprüngliche Absicht, Vererbung als C ++ - Sprachfunktion einzuführen . Dies ist der Grund, warum Andreys Antwort weiterhin die akzeptierte bleibt.
scouring C++11's standard I couldn't conclusively say that it calls out accessing/inspecting a non-active union member is undefined [...] All I could find was §9.5/1
...Ja wirklich? Sie eine Ausnahme zitieren Note , nicht die wichtigsten Punkt gleich zu Beginn des Absatzes : „In einer Union, höchstens einer der nicht-statischen Datenelemente können jederzeit aktiv sein, dass der Wert von höchstens eines von Die nicht statischen Datenelemente können jederzeit in einer Union gespeichert werden. " - und bis zu p4: "Im Allgemeinen muss man explizite Destruktoraufrufe verwenden und neue Operatoren platzieren, um das aktive Mitglied einer Gewerkschaft zu ändern "
b, g, r,
unda
kann nicht zusammenhängend sein und somit nicht mit dem Layout von a übereinstimmenuint32_t
. Dies ist zusätzlich zu den Endianess-Problemen, auf die andere hingewiesen haben.