>>157374Die naheliegendste Erklärung für Felix ist, dass {0} wie in vorherigen Versionen von Clang entgegen der Intuition kein spezielles Muster für das Nullen des Unions ist (vor allem, wenn das erste Mitglied kein Standard-Datentyp ist, bei dem der Nullwert nicht vollständig aus Nullbits besteht), sondern schlicht das erste Mitglied auf Null setzt und jetzt das implizite Leeren des Rests wegfällt.
Felix hat sich aufgrund dieses konstruierten Beispiels mit Godbolt angesehen, was das in der Praxis bedeutet:
extern void dosomething(long *);
void bla() {
union { int i; long l; } U = {-42};
dosomething(&U.l);
}
x86_64, gcc 14.3, -O0: gesamtes Union wird genullt und dann die unteren 32 Bit geschrieben
x86_64, gcc 14.3, -O1: die oberen 32 Bit werden explizit auf Null gesetzt und dann die unteren 32 Bit geschrieben
x86_64, gcc 14.3, -O2/-O3: 32 Bit werden in EAX geladen, damit implizit die oberen 32 Bit des Registers auf Null gesetzt und RAX in das Union geschrieben
x86_64, gcc 15.1, -O0: nur die unteren 32 Bit werden geschrieben
x86_64, gcc 15.1, -O1: wie gcc 14.3
x86_64, gcc 15.1, -O2/-O3: wie gcc 14.3
ARM64-Ausgabe verhält sich jeweils wie x86_64, nur dass für -O1 die stp-Instruktion in Kombination mit dem Nullregister benutzt wird.
x86_64, clang, -O0: 64 Bit mit Nullpadding werden aus static storage gelesen und geschrieben
x86_64, clang, -O1/-O2/-O3: wie gcc -O2
ARM64-Ausgabe verhält sich jeweils wie x86_64, d.h. mit Optimierungen werden die oberen 32 Bit eines 64-Bit-Registers implizit genullt.
x86_64, ARM64 MSVC unabhängig von Optimizer-Flags: nur die unteren 32 Bit werden geschrieben
Für dieses Beispiel auf diesen zwei Plattformen macht GCC 15 also zufälligerweise etwas Sinnvolles, außer wenn Optimierungen deaktiviert sind.