Eu já usei sindicatos confortavelmente; hoje fiquei alarmado quando li este post e soube que esse 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
Na verdade, é um comportamento indefinido, ou seja, a leitura de um membro do sindicato que não seja o recentemente escrito para leva a um comportamento indefinido. Se esse não é o uso pretendido dos sindicatos, o que é? Alguém pode explicar isso de forma elaborada?
Atualizar:
Eu queria esclarecer algumas coisas em retrospectiva.
- A resposta para a pergunta não é a mesma para C e C ++; meu eu mais jovem ignorante o identificou como C e C ++.
- Após vasculhar o padrão do C ++ 11, não pude dizer conclusivamente que o acesso / inspeção de um membro do sindicato não ativo é indefinido / não especificado / definido pela implementação. Tudo o que encontrei foi §9.5 / 1:
Se uma união de layout padrão contiver várias estruturas de layout padrão que compartilham uma sequência inicial comum, e se um objeto desse tipo de união de layout padrão contiver uma das estruturas de layout padrão, será permitido inspecionar a sequência inicial comum de qualquer de membros de estrutura de layout padrão. §9.2 / 19: Duas estruturas de layout padrão compartilham uma sequência inicial comum se os membros correspondentes tiverem tipos compatíveis com o layout e nenhum membro for um campo de bits ou ambos forem campos de bits com a mesma largura para uma sequência de uma ou mais inicial membros.
- Enquanto estiver em C, ( C99 TC3 - DR 283 em diante), é legal fazê-lo ( obrigado a Pascal Cuoq por trazer isso à tona). No entanto, tentar fazê- lo ainda pode levar a um comportamento indefinido , se o valor lido for inválido (a chamada "representação de interceptação") para o tipo pelo qual é lido. Caso contrário, o valor lido é a implementação definida.
O C89 / 90 chamou isso de comportamento não especificado (Anexo J) e o livro da K&R diz que sua implementação está definida. Citação de K&R:
Esse é o objetivo de uma união - uma única variável que pode legitimamente conter qualquer um de vários tipos. [...] desde que o uso seja consistente: o tipo recuperado deve ser o tipo armazenado mais recentemente. É responsabilidade do programador acompanhar qual tipo está atualmente armazenado em uma união; os resultados dependem da implementação se algo for armazenado como um tipo e extraído como outro.
Extrato do TC ++ PL da Stroustrup (ênfase minha)
O uso de uniões pode ser essencial para a compatibilidade de dados [...] às vezes mal utilizados para "conversão de tipo ".
Acima de tudo, esta questão (cujo título permanece inalterado desde a minha ASK) foi colocada com a intenção de compreender o propósito de sindicatos e não no que o padrão permite por exemplo, usando herança para a reutilização de código é, naturalmente, permitido pelo C ++ padrão, mas não era o objetivo ou a intenção original de introduzir herança como um recurso da linguagem C ++ . Essa é a razão pela qual a resposta de Andrey continua sendo a aceita.
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
...realmente? você cita uma nota de exceção , não o ponto principal logo no início do parágrafo : "Em uma união, no máximo um dos membros de dados não estáticos pode estar ativo a qualquer momento, ou seja, o valor de no máximo um dos os membros de dados não estáticos podem ser armazenados em uma união a qualquer momento ". - e até a p4: "Em geral, é preciso usar chamadas explícitas de destruidores e posicionar novos operadores para alterar o membro ativo de uma união "
b, g, r,
ea
pode não ser contíguo e, portanto, não coincidir com o layout de auint32_t
. Isso é um acréscimo às questões de Endianess que outros apontaram.