Ich hatte den Eindruck, dass der Zugriff auf ein union
anderes Mitglied als den letzten Satz UB ist, aber ich kann anscheinend keine solide Referenz finden (außer Antworten, die behaupten, es sei UB, aber ohne Unterstützung durch den Standard).
Ist es also undefiniertes Verhalten?
c++
undefined-behavior
language-lawyer
unions
Luchian Grigore
quelle
quelle
Antworten:
Die Verwirrung ist, dass C explizit Typ-Punning durch eine Union erlaubt, während C ++ (c ++ 11) hat keine solche Erlaubnis.
Die Situation mit C ++:
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):
Besonders interessant wird es, wenn wir lesen
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
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:
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:
char
Array-Speicher und zurück kopiert (3.9: 2), oderDer 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.
quelle
memcpy
Implementierungen (Zugriff auf Objekte mitunsigned char
l-Werten) nicht zugelassen, Zugriffe auf*p
After nicht zugelassenint *p = 0; const int *const *pp = &p;
(obwohl die implizite Konvertierung vonint**
toconst int*const*
gültig ist) und sogar den Zugriffc
nachher nicht zugelassenstruct S s; const S &c = s;
. CWG Ausgabe 616 . Erlaubt der neue Wortlaut dies? Es gibt auch [basic.lval].&
Operator bedeutet, wenn er auf ein Gewerkschaftsmitglied angewendet wird. Ich würde denken, dass der resultierende Zeiger verwendet werden sollte, um zumindest bis zur nächsten direkten oder indirekten Verwendung eines anderen Mitgliedswerts auf das Mitglied zuzugreifen, aber in gcc ist der Zeiger nicht einmal so lange verwendbar, was eine Frage aufwirft, was der&
Betreiber soll bedeuten.Der C ++ 11-Standard sagt es so
Wenn nur ein Wert gespeichert ist, wie können Sie einen anderen lesen? Es ist einfach nicht da.
Die gcc-Dokumentation listet dies unter Implementierungsdefiniertes Verhalten auf
Dies zeigt an, dass dies vom C-Standard nicht verlangt wird.
05.01.2016: Durch die Kommentare wurde ich mit dem C99-Fehlerbericht Nr. 283 verknüpft , der dem C-Standarddokument einen ähnlichen Text als Fußnote hinzufügt:
Ich bin mir nicht sicher, ob es viel klarstellt, wenn man bedenkt, dass eine Fußnote für den Standard nicht normativ ist.
quelle
Ich denke, der Standard kommt dem undefinierten Verhalten am nächsten, wenn er das Verhalten für eine Union definiert, die eine gemeinsame Anfangssequenz enthält (C99, §6.5.2.3 / 5):
C ++ 11 bietet ähnliche Anforderungen / Berechtigungen in §9.2 / 19:
Obwohl es keiner direkt angibt, haben beide eine starke Implikation, dass das "Inspizieren" (Lesen) eines Mitglieds nur dann "erlaubt" ist , wenn 1) es (ein Teil) des zuletzt geschriebenen Mitglieds ist oder 2) Teil einer gemeinsamen Initiale ist Reihenfolge.
Das ist keine direkte Aussage, dass es undefiniertes Verhalten ist, etwas anderes zu tun, aber es ist das nächste, von dem ich weiß.
quelle
union
s undefiniert sind, da ich von einem bestimmten Blog den Eindruck bekommen hatte, dass dies in Ordnung ist, und mehrere große Strukturen und Projekte darum herum gebaut habe. Jetzt denke ich, dass ich vielleicht doch in Ordnung bin, da meineunion
s Klassen mit den gleichen Typen an der Vorderseite enthaltenunion
enthält ? Ich würde annehmen, dass dieser Vorbehalt auch hier gilt, aber es ist sehr bewusst formuliert, nur s zuzulassen . Zum Glück verwende ich diese bereits anstelle von rohen Grundelementen: Ouint8_t
class Something { uint8_t myByte; [...] };
struct
Was in den verfügbaren Antworten noch nicht erwähnt wird, ist die Fußnote 37 in Abschnitt 21 Absatz 21.2.5:
Diese Anforderung scheint eindeutig zu implizieren, dass Sie nicht in ein Mitglied schreiben und in einem anderen lesen dürfen. In diesem Fall kann es sich um ein undefiniertes Verhalten aufgrund fehlender Spezifikation handeln.
quelle
Ich erkläre das gut mit einem Beispiel.
Nehmen wir an, wir haben die folgende Vereinigung:
Ich gehe davon aus, dass dies
sizeof(int)
4 ergibt und dass dies 2sizeof(short)
ergibt.Wenn Sie so gut schreiben
union A a = {10}
, erstellen Sie eine neue Variable vom Typ A, in die der Wert 10 eingegeben wird.Ihr Gedächtnis sollte folgendermaßen aussehen: (Denken Sie daran, dass alle Gewerkschaftsmitglieder denselben Standort erhalten.)
Wie Sie sehen konnten, ist der Wert von ax 10, der Wert von ay 1 ist 10 und der Wert von ay [0] ist 0.
Was passiert nun, wenn ich das mache?
Unsere Erinnerung wird so aussehen:
Dadurch wird der Wert von ax auf 2424842 (in Dezimalzahl) geändert.
Wenn Ihre Gewerkschaft einen Float oder Double hat, ist Ihre Speicherzuordnung aufgrund der Art und Weise, wie Sie genaue Zahlen speichern, eher ein Chaos. Weitere Informationen finden Sie hier .
quelle