Ho usato i sindacati prima comodamente; oggi sono stato allarmato quando ho letto questo post e ho scoperto che questo codice
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
è in realtà un comportamento indefinito Vale a dire leggere da un membro del sindacato diverso da quello scritto di recente porta a un comportamento indefinito. Se questo non è l'uso previsto dei sindacati, che cos'è? Qualcuno può spiegarlo in modo elaborato?
Aggiornare:
Volevo chiarire alcune cose con il senno di poi.
- La risposta alla domanda non è la stessa per C e C ++; il mio io più giovane ignorante lo ha etichettato sia come C che C ++.
- Dopo aver passato in rassegna lo standard di C ++ 11, non ho potuto dire in modo definitivo che invoca / ispeziona un membro sindacale non attivo non definito / non specificato / definito dall'implementazione. Tutto quello che ho trovato è stato §9.5 / 1:
Se un'unione di layout standard contiene diverse strutture di layout standard che condividono una sequenza iniziale comune e se un oggetto di questo tipo di unione di layout standard contiene una delle strutture di layout standard, è consentito ispezionare la sequenza iniziale comune di qualsiasi dei membri della struttura a layout standard. §9.2 / 19: Due strutture di layout standard condividono una sequenza iniziale comune se i membri corrispondenti hanno tipi compatibili con il layout e nessuno dei due membri è un campo di bit o entrambi sono campi di bit con la stessa larghezza per una sequenza di una o più iniziali membri.
- Mentre sei in C, ( C99 TC3 - DR 283 in poi) è legale farlo ( grazie a Pascal Cuoq per averlo menzionato ). Tuttavia, tentare di farlo può comunque portare a comportamenti indefiniti , se il valore letto risulta non valido (la cosiddetta "rappresentazione trap") per il tipo che viene letto. Altrimenti, il valore letto è definito dall'implementazione.
C89 / 90 lo ha definito sotto un comportamento non specificato (Allegato J) e il libro di K&R afferma che la sua implementazione è stata definita. Citazione da K&R:
Questo è lo scopo di un'unione - una singola variabile che può legittimamente contenere uno di diversi tipi. [...] purché l'uso sia coerente: il tipo recuperato deve essere il tipo memorizzato più di recente. È responsabilità del programmatore tenere traccia di quale tipo è attualmente memorizzato in un sindacato; i risultati dipendono dall'implementazione se qualcosa viene archiviato come un tipo ed estratto come un altro.
Estratto dal TC ++ PL di Stroustrup (il mio accento è mio)
L'uso dei sindacati può essere essenziale per la compatibilità dei dati [...] talvolta utilizzati in modo improprio per la "conversione del tipo ".
Soprattutto, questa domanda (il cui titolo rimane invariato dalla mia domanda) è stata posta con l'intenzione di comprendere lo scopo dei sindacati E non su ciò che lo standard consente Ad es. L'uso dell'ereditarietà per il riutilizzo del codice è, ovviamente, consentito dallo standard C ++, ma non era lo scopo o l'intenzione originale di introdurre l'ereditarietà come funzionalità del linguaggio C ++ . Questo è il motivo per cui la risposta di Andrey continua a rimanere quella accettata.
scouring C++11's standard I couldn't conclusively say that it calls out accessing/inspecting a non-active union member is undefined [...] All I could find was §9.5/1
...veramente? si cita una nota di eccezione , non il punto principale all'inizio del paragrafo : "In un'unione, al massimo uno dei membri di dati non statici può essere attivo in qualsiasi momento, ovvero il valore di al massimo uno dei i membri di dati non statici possono essere archiviati in un sindacato in qualsiasi momento. " - e fino a p4: "In generale, si devono usare chiamate esplicite al distruttore e posizionare nuovi operatori per cambiare il membro attivo di un sindacato "
b, g, r,
ea
potrebbe non essere contiguo, e quindi non corrispondere al layout di auint32_t
. Ciò si aggiunge alle questioni di Endianess che altri hanno sottolineato.