Die Verwirrung ist, dass C explizit Typ-Punning durch eine Union erlaubt, während C ++ (c ++ 11) hat keine solche Erlaubnis.
c11
6.5.2.3 Struktur und Gewerkschaftsmitglieder
95) Wenn das Element, das zum Lesen des Inhalts eines Vereinigungsobjekts verwendet wird, nicht mit dem Element identisch ist, das zuletzt zum Speichern eines Werts im Objekt verwendet wurde, wird der entsprechende Teil der Objektdarstellung des Werts als Objektdarstellung im neuen Objekt neu interpretiert Typ wie in 6.2.6 beschrieben (ein Prozess, der manchmal als "Typ Punning" bezeichnet wird). Dies könnte eine Trap-Darstellung sein.
Die Situation mit C ++:
c ++ 11
9.5 Gewerkschaften [class.union]
In einer Union kann höchstens eines der nicht statischen Datenelemente jederzeit aktiv sein, dh der Wert von höchstens einem der nicht statischen Datenelemente kann jederzeit in einer Union gespeichert werden.
C ++ hat später eine Sprache, die die Verwendung von Gewerkschaften erlaubt, die struct
s mit gemeinsamen Anfangssequenzen enthalten. Dies erlaubt jedoch keine Typ-Punning.
Um festzustellen, ob Union Type-Punning ist in C ++ , müssen wir weiter suchen. Erinnere dich daranc99 ist eine normative Referenz für C ++ 11 (und C99 hat eine ähnliche Sprache wie C11, die das Punning von Unionstypen ermöglicht):
3.9 Typen [basic.types]
4 - Die Objektdarstellung eines Objekts vom Typ T ist die Folge von N vorzeichenlosen Zeichenobjekten, die vom Objekt vom Typ T aufgenommen werden, wobei N gleich sizeof (T) ist. Die Wertdarstellung eines Objekts ist die Menge von Bits, die den Wert vom Typ T enthalten. Bei trivial kopierbaren Typen ist die Wertdarstellung eine Menge von Bits in der Objektdarstellung, die einen Wert bestimmt, der ein diskretes Element einer Implementierung ist. definierter Wertesatz. 42
42) Es ist beabsichtigt, dass das Speichermodell von C ++ mit dem von ISO / IEC 9899 Programmiersprache C kompatibel ist.
Besonders interessant wird es, wenn wir lesen
3.8 Objektlebensdauer [basic.life]
Die Lebensdauer eines Objekts vom Typ T beginnt, wenn: - eine Speicherung mit der richtigen Ausrichtung und Größe für Typ T erhalten wird und - wenn das Objekt eine nicht triviale Initialisierung aufweist, ist seine Initialisierung abgeschlossen.
Für einen primitiven Typ (der ipso facto eine triviale Initialisierung aufweist), der in einer Vereinigung enthalten ist, umfasst die Lebensdauer des Objekts mindestens die Lebensdauer der Vereinigung selbst. Dies ermöglicht es uns, aufzurufen
3.9.2 Verbindungstypen [basic.compound]
Befindet sich ein Objekt vom Typ T an einer Adresse A, so soll ein Zeiger vom Typ cv T *, dessen Wert die Adresse A ist, auf dieses Objekt zeigen, unabhängig davon, wie der Wert erhalten wurde.
Unter der Annahme, dass es sich bei der Operation, an der wir interessiert sind, um Typ-Punning handelt, dh den Wert eines nicht aktiven Gewerkschaftsmitglieds annimmt, und vorausgesetzt, dass wir einen gültigen Verweis auf das Objekt haben, auf das sich dieses Mitglied bezieht, ist diese Operation von Wert -Wertumwandlung:
4.1 L-Wert-zu-Wert-Konvertierung [conv.lval]
Ein Gl-Wert eines Nicht-Funktions- oder Nicht-Array-Typs T
kann in einen Wert umgewandelt werden. Wenn T
es sich um einen unvollständigen Typ handelt, ist ein Programm, das diese Konvertierung erfordert, fehlerhaft. Wenn das Objekt, auf das sich der Wert bezieht, kein Objekt vom Typ T
und kein Objekt eines Typs ist, von dem abgeleitet wurde T
, oder wenn das Objekt nicht initialisiert ist, hat ein Programm, das diese Konvertierung erfordert, ein nicht definiertes Verhalten.
Die Frage ist dann, ob ein Objekt, das ein nicht aktives Gewerkschaftsmitglied ist, durch Speichern im aktiven Gewerkschaftsmitglied initialisiert wird. Soweit ich das beurteilen kann, ist dies nicht der Fall und obwohl:
- Eine Union wird in den
char
Array-Speicher und zurück kopiert (3.9: 2), oder
- Eine Vereinigung wird byteweise in eine andere Vereinigung des gleichen Typs kopiert (3.9: 3), oder
- Auf eine Union wird dann über Sprachgrenzen hinweg von einem Programmelement zugegriffen, das ISO / IEC 9899 (soweit definiert) entspricht (3.9: 4, Anmerkung 42)
Der Zugriff eines nicht aktiven Mitglieds auf eine Union ist definiert und folgt der Objekt- und Wertdarstellung. Der Zugriff ohne eine der oben genannten Interpositionen ist ein undefiniertes Verhalten. Dies hat Auswirkungen auf die Optimierungen, die für ein solches Programm durchgeführt werden dürfen, da bei der Implementierung natürlich davon ausgegangen werden kann, dass kein undefiniertes Verhalten auftritt.
Das heißt, obwohl wir einem nicht aktiven Gewerkschaftsmitglied einen legitimen Wert bilden können (weshalb die Zuordnung zu einem nicht aktiven Mitglied ohne Konstruktion in Ordnung ist), wird dies als nicht initialisiert angesehen.