Verursacht das Lesen in ein anderes Variantenmitglied einer Union, das denselben Typ wie die aktive Variante hat, UB?

Lesezeit: 4 Minuten

Benutzeravatar von xmh0511
xmh0511

union A{
  int a;
  int b;
};
int main(){
  A u = {.a = 0};
  int r = u.b; // #1 Is this UB?
}

[class.union] sagt

In einer Union ist ein nicht statisches Datenelement aktiv, wenn sein Name auf ein Objekt verweist, dessen Lebensdauer begonnen und noch nicht beendet ist ([basic.life]). Höchstens eines der nicht statischen Datenelemente eines Objekts vom Typ Union kann jederzeit aktiv sein, d. h. der Wert von höchstens einem der nicht statischen Datenelemente kann jederzeit in einer Union gespeichert werden.

Nur in diesem Beispiel A::a ist also aktiv [basic.life] p7 sagt

Das Programm weist undefiniertes Verhalten auf, wenn:

  • Der GL-Wert wird verwendet, um auf das Objekt zuzugreifen, oder

#1 versucht, auf das Objekt zuzugreifen, dessen Lebensdauer noch nicht begonnen hat. Verursacht dieser Zugriff UB? Wenn ja, ist diese Anforderung zu restriktiv?

Übrigens: Stellt der C-Standard in diesem Beispiel die gleichen Anforderungen? Oder hat C in diesem Fall eine lockerere Anforderung?

Aktualisieren

In C-Standardfinde ich eine Notiz, die besagt

Wenn das Mitglied, das zum Lesen des Inhalts eines Union-Objekts verwendet wird, nicht mit dem Mitglied übereinstimmt, das zuletzt zum Speichern eines Werts im Objekt verwendet wurde, wird der entsprechende Teil der Objektdarstellung des Werts wie beschrieben als Objektdarstellung im neuen Typ neu interpretiert in 6.2.6 (ein Prozess, der manchmal als Type Punning bezeichnet wird). Dies könnte eine Darstellung ohne Wert sein.

Dies bedeutet, dass es in C zulässig ist. https://eel.is/c++draft/diff.iso

Unterabschnitt [diff.iso] listet die Unterschiede zwischen C++ und ISO C zusätzlich zu den oben aufgeführten Kapiteln dieses Dokuments auf.

weist nicht auf den Unterschied hin.

  • @463035818_is_not_a_number Nein, das ist nicht dasselbe. Der formale Wortlaut lautet [[class.mem.general] S.26](eel.is/c++draft/class.mem#general-26), Voraussetzung ist, dass diese beiden Varianten vom Strukturtyp sein sollten. Darüber hinaus bezieht sich das Konzept der „gemeinsamen Anfangssequenz“ auf eine „Standard-Layout-Struktur“.

    – xmh0511

    24. Mai um 12:32 Uhr


  • @NathanOliver Siehe eel.is/c++draft/basic.life#1werden Sie feststellen, wie die Lebensdauer einer Variante einer Union beginnt (im Zitat „nur“ hervorgehoben).

    – xmh0511

    24. Mai um 12:48 Uhr


  • [diff.iso] ist informativ und nicht normativ, daher ist das Weglassen eines Unterschieds zwischen C und C++ vermutlich ein Versehen und keine maßgebliche Aussage. Selbst wenn es normativ wäre, wäre es nur für C++ maßgebend und hätte keine Autorität über den C-Standard.

    – Eric Postpischil

    24. Mai um 13:14 Uhr

  • Ich denke, das ist immer noch größtenteils richtig, stackoverflow.com/questions/25664848/unions-and-type-punning, also vielleicht ein Duplikat.

    – Lundin

    24. Mai um 13:36 Uhr

  • Ok, da Sie die Frage im Wesentlichen selbst beantwortet haben, schließe ich als Betrüger, es sei denn, jemand hat neue Informationen zu den C23-C++23-Versionen …? Normativer Text in C++ ist das Zitat „Höchstens eines der nichtstatischen Datenelemente eines Objekts vom Unionstyp kann jederzeit aktiv sein“, normativer Text in C ist 6.5.2.3 „Ein Postfix-Ausdruck, gefolgt vom .-Operator und.“ Ein Bezeichner bezeichnet ein Mitglied einer Struktur oder eines Unionsobjekts. Der Wert ist der des benannten Mitglieds“ (die zitierte Fußnote verweist auf diesen Text). Und [diff.iso] ist gänzlich abzulehnen.

    – Lundin

    24. Mai um 14:21 Uhr

Ich denke, in C++ ist dies ein undefiniertes Verhalten gemäß dem ersten Standardzitat in der Frage selbst: Es gibt dort keine Ausnahme für den Fall derselben Datenelementtypen.

Und große Compiler scheinen dieser Lesart zuzustimmen und solchen Code in konstanten Ausdrücken zu verbieten:

union A{
  int a;
  int b;
};

constexpr int f() {
  A u = {.a = 0};
  return u.b;
}

constexpr int x = f();

Online-Demo: https://gcc.godbolt.org/z/We4zYzdaa

Clangs Fehler:

read of member 'b' of union with active member 'a' is not allowed in a constant expression

GCC-Fehler:

accessing 'A::b' member instead of initialized 'A::a' member in constant expression

Fehler von MSVC:

failure was caused by accessing a non-active member of a union

  • Interessanterweise lehnen alle Compiler auch das sehr ähnliche, aber explizit erlaubte Beispiel von ab [class.mem.general]/5. DEMO.

    – dfrib

    25. Mai um 16:46 Uhr

  • @dfrib Die allgemeine Anfangssequenzregel ist in einem Kontext mit konstanten Ausdrücken nicht zulässig, da dies der Fall ist ändert das aktive Mitglied nicht

    – Shafik Yaghmour

    25. Mai um 21:21 Uhr

  • @ShafikYaghmour Das würde es erklären, danke. Würde der Wortlaut von class.mem.general „[…] Das Verhalten ist so, als ob Das entsprechende Mitglied von T1 wurde nominiert.“ Brauchen Sie etwas Umschreibung oder Klarstellung, oder ist irgendwo klar, dass „als ob“ nicht einen Sonderfall bedeutet, der den von expr.const/5.10 ausschließt?

    – dfrib

    26. Mai um 8:44


Verursacht das Lesen in ein anderes Variantenmitglied einer Union, das denselben Typ wie die aktive Variante hat, UB?

Die Regel ist klar. Ein Mitglied ist aktiv. Das Lesen inaktiv ist UB.

Verursacht dieser Zugriff UB?

Ja.

Wenn ja, ist diese Anforderung zu restriktiv?

Keine Ahnung. Subjektiv: Nichts für mich. Es ist in Ordnung. Ich sehe keinen Wert darin, zwei Mitglieder desselben Typs in einer Gewerkschaft zu haben und dann auf das eine oder das andere zuzugreifen.

Stellt der C-Standard in diesem Beispiel die gleichen Anforderungen?

Nein. Eines der Beispiele dafür, dass C und C++ unterschiedlich sind.

Hat C in diesem Fall eine lockerere Anforderung?

Ja. In C können Sie jedes Mitglied einer Gewerkschaft lesen, das Sie möchten. Voraussetzung ist, dass der ermittelte Wert keine Fallendarstellung darstellt.

Verwandte Themen: Gewerkschaften und Wortspiele

1453940cookie-checkVerursacht das Lesen in ein anderes Variantenmitglied einer Union, das denselben Typ wie die aktive Variante hat, UB?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy