He usado los sindicatos antes cómodamente; hoy me alarmó cuando leí esta publicación y supe que este código
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
en realidad es un comportamiento indefinido, es decir, leer de un miembro del sindicato diferente al que se escribió recientemente conduce a un comportamiento indefinido. Si este no es el uso previsto de los sindicatos, ¿qué es? ¿Puede alguien explicarlo detalladamente?
Actualizar:
Quería aclarar algunas cosas en retrospectiva.
- La respuesta a la pregunta no es la misma para C y C ++; mi joven ignorante lo etiquetó como C y C ++.
- Después de revisar el estándar de C ++ 11, no podría decir de manera concluyente que exija que el acceso / inspección de un miembro del sindicato no activo sea indefinido / no especificado / definido por la implementación. Todo lo que pude encontrar fue §9.5 / 1:
Si una unión de diseño estándar contiene varias estructuras de diseño estándar que comparten una secuencia inicial común, y si un objeto de este tipo de unión de diseño estándar contiene una de las estructuras de diseño estándar, se permite inspeccionar la secuencia inicial común de cualquier de miembros de estructura de diseño estándar. §9.2 / 19: Dos estructuras de diseño estándar comparten una secuencia inicial común si los miembros correspondientes tienen tipos compatibles con el diseño y ninguno de los miembros es un campo de bits o ambos son campos de bits con el mismo ancho para una secuencia de uno o más iniciales miembros.
- Mientras que en C, ( C99 TC3 - DR 283 en adelante) es legal hacerlo ( gracias a Pascal Cuoq por mencionar esto). Sin embargo, intentar hacerlo puede conducir a un comportamiento indefinido , si el valor leído no es válido (lo que se denomina "representación de trampa") para el tipo que se lee. De lo contrario, el valor leído es la implementación definida.
C89 / 90 lo llamó bajo un comportamiento no especificado (Anexo J) y el libro de K&R dice que su implementación está definida. Cita de K&R:
Este es el propósito de una unión, una variable única que puede contener legítimamente uno de varios tipos. [...] siempre que el uso sea consistente: el tipo recuperado debe ser el tipo almacenado más recientemente. Es responsabilidad del programador hacer un seguimiento de qué tipo se almacena actualmente en una unión; los resultados dependen de la implementación si algo se almacena como un tipo y se extrae como otro.
Extracto de TC ++ PL de Stroustrup (énfasis mío)
El uso de uniones puede ser esencial para la compatibilidad de los datos, a veces [...] mal utilizados para la "conversión de tipos ".
Sobre todo, esta pregunta (cuyo título permanece sin cambios desde mi solicitud) se planteó con la intención de comprender el propósito de las uniones Y no sobre lo que permite el estándar . No era el propósito o la intención original de introducir la herencia como una característica del lenguaje C ++ . Esta es la razón por la cual la respuesta de Andrey sigue siendo la aceptada.
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
...¿De Verdad? Usted cita una nota de excepción , no el punto principal justo al comienzo del párrafo : "En una unión, como máximo uno de los miembros de datos no estáticos puede estar activo en cualquier momento, es decir, el valor de como máximo uno de los miembros de datos no estáticos se pueden almacenar en una unión en cualquier momento ". - y hasta p4: "En general, uno debe usar llamadas explícitas de destructores y colocar nuevos operadores para cambiar el miembro activo de un sindicato "
b, g, r,
ya
pueden no ser contiguos, por lo que no coincida con el diseño de unuint32_t
. Esto se suma a los problemas de Endianess que otros han señalado.