Ich habe Gewerkschaften früher bequem genutzt; heute war ich alarmiert, als ich las diese Stelle 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 eigentlich undefiniertes Verhalten, d.h. das Lesen aus einem anderen Mitglied der Union als dem, in das gerade geschrieben wurde, führt zu undefiniertem Verhalten. Wenn dies nicht die beabsichtigte Verwendung von Unions ist, was dann? Kann mir das bitte jemand genauer erklären?
Aktualisierung:
Ich wollte im Nachhinein ein paar Dinge klarstellen.
-
Die Antwort auf diese Frage ist für C und C++ nicht dieselbe; mein unwissendes jüngeres Ich hat sie sowohl als C als auch als C++ bezeichnet.
-
Nachdem ich den C++11-Standard durchforstet hatte, konnte ich nicht schlüssig sagen, dass der Zugriff auf ein nicht aktives Unionsmitglied undefiniert/unspezifisch/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, ist es erlaubt, die gemeinsame Anfangssequenz eines beliebigen Standard-Layout-Struktur-Mitglieds zu untersuchen. §9.2/19: Zwei Standard-Layout-Strukturen haben eine gemeinsame Anfangssequenz, wenn die entsprechenden Mitglieder layout-kompatible Typen haben und entweder keines der beiden Mitglieder ein Bit-Feld ist oder beide Bit-Felder mit der gleichen Breite für eine Sequenz von einem oder mehreren Anfangsmitgliedern sind.
-
Während in C, ( C99 TC3 - DR 283 ab), ist es legal, dies zu tun ( Dank an Pascal Cuoq für die Erwähnung dieses Themas). Der Versuch, dies zu tun, ist jedoch es kann immer noch zu undefiniertem Verhalten führen wenn der gelesene Wert für den Typ, über den er gelesen wird, ungültig ist (so genannte "Trap-Darstellung"). Andernfalls ist der gelesene Wert durch die Implementierung definiert.
-
In C89/90 wurde dies unter "unspecified behavior" (Annex J) aufgeführt, und in K&Rs Buch heißt es, es sei "implementation defined". Zitat aus K&R:
Dies ist der Zweck einer Vereinigung - eine einzelne Variable, die legitimerweise einen von mehreren Typen enthalten kann. [...] solange die Verwendung konsistent ist: der Typ, der abgerufen wird, muss der Typ sein, der zuletzt gespeichert wurde. Es liegt in der Verantwortung des Programmierers, den Überblick darüber zu behalten, welcher Typ gerade in einer Union gespeichert ist; die Ergebnisse sind von der Implementierung abhängig, wenn etwas als ein Typ gespeichert und als ein anderer extrahiert wird.
-
Auszug aus Stroustrups TC++PL (Hervorhebung von mir)
Die Verwendung von Unions kann für die Kompatibilität von Daten wesentlich sein [...] manchmal fälschlicherweise für "Typumwandlung" verwendet ".
Vor allem wurde diese Frage (deren Titel seit meiner Anfrage unverändert geblieben ist) in der Absicht gestellt, den Zweck von Gewerkschaften zu verstehen UND nicht, was die Norm erlaubt Die Verwendung von Vererbung zur Wiederverwendung von Code ist natürlich nach dem C++-Standard zulässig, aber es war nicht der Zweck oder die ursprüngliche Absicht der Einführung der Vererbung als ein Merkmal der Sprache C++ . Dies ist der Grund dafür, dass die Antwort von Andrey weiterhin die akzeptierte Antwort ist.