Em C, um union é um tipo de dado especial que permite que diferentes tipos de dados ocupem a mesma área de memória. Embora um union possa ter vários membros, apenas um deles pode conter um valor válido em qualquer momento específico. Essa caracetrística o torna uma ferramenta eficaz para gerenciar a memória de forma otimizada.
Definindo um Union
A declaração de um union é feita utilizando a palavra-chave union, de maneira semelhante à declaração de structs. A sintaxe básica é a seguinte:
union NomeDoUnion {
tipo membro1;
tipo membro2;
// ... outros membros
} variavelUnionOpcional;
O NomeDoUnion é um identificador opcional para o tipo de union. Cada membro é uma declaração de variável padrão. Opcionalmente, você pode declarar variáveis do tipo union no final da definição. Por exemplo, um union chamado Valor pode conter um inteiro, um ponto flutuante e um array de caracteres:
union Valor {
int numeroInteiro;
float numeroFlutuante;
char texto[25];
};
Uma variável do tipo Valor pode, em momentos diferentes, armazenar um int, um float ou uma string. Essencialmente, uma única variável (compartilhando o mesmo espaço de memória) pode abrigar dados de diferentes tipos.
O tamanho em memória de um union é determinado pelo tamanho do seu maior membro. No exemplo acima, o union Valor ocuparia 25 bytes, pois o array texto é o membro com o maior requisito de memória. Veja um exemplo de como verificar o tamanho ocupado:
#include <stdio.h>
union Valor {
int numeroInteiro;
float numeroFlutuante;
char texto[25];
};
int main() {
union Valor dados;
printf("Tamanho ocupado pela union: %zu bytes\n", sizeof(dados));
return 0;
}
A execução deste código resultará em:
Tamanho ocupado pela union: 25 bytes
Acessando Membros de um Union
Para acessar os membros de um union, utiliza-se o operador de acesso a membros (.). Este operador é colocado entre o nome da variável union e o nome do membro desejado. O exemplo a seguir demonstra o uso de um union:
#include <stdio.h>
#include <string.h>
union Valor {
int numeroInteiro;
float numeroFlutuante;
char texto[25];
};
int main() {
union Valor dados;
dados.numeroInteiro = 15;
printf("Valor do inteiro: %d\n", dados.numeroInteiro);
dados.numeroFlutuante = 3.14159f;
printf("Valor do flutuante: %f\n", dados.numeroFlutuante);
strcpy(dados.texto, "Exemplo de Union");
printf("Valor do texto: %s\n", dados.texto);
return 0;
}
Ao executar o código acima, a saída pode parecer confusa para os membros numeroInteiro e numeroFlutuante após a atribuição de texto. Isso ocorre porque a última escrita (strcpy) sobrescreveu a memória. O resultado esperado seria:
Valor do inteiro: 15
Valor do flutuante: 3.141590
Valor do texto: Exemplo de Union
No entanto, se interpretarmos os bytes da memória de forma incorreta após múltiplas atribuições, podemos obter resultados como:
Valor do inteiro: 1917853763 // Valor corrompido
Valor do flutuante: 4122360580327794860452759994368.000000 // Valor corrompido
Valor do texto: Exemplo de Union
O comportamento correto e o propósito principal de um union são evidenciados quando apenas um membro é acessado em determinado momento. A próxima demonstração ilustra isso:
#include <stdio.h>
#include <string.h>
union Valor {
int numeroInteiro;
float numeroFlutuante;
char texto[25];
};
int main() {
union Valor dados;
dados.numeroInteiro = 10;
printf("Acessando o inteiro: %d\n", dados.numeroInteiro);
dados.numeroFlutuante = 220.5f;
printf("Acessando o flutuante: %f\n", dados.numeroFlutuante);
strcpy(dados.texto, "Manipulacao C");
printf("Acessando o texto: %s\n", dados.texto);
return 0;
}
A execução deste código produzirá:
Acessando o inteiro: 10
Acessando o flutuante: 220.500000
Acessando o texto: Manipulacao C
Neste cenário, todos os membros são acessados corretamente porque, em cada ponto de acesso, apenas o membro que foi atribuído mais recentemente é considerado. As atribuições subsequentes a outros membros sobrescrevem os dados anteriores na mesma área de memória.
Pontos Chave
- Compartilhamento de Memória: Todos os membros de um
unioncompartilham o mesmo local de memória. Em qualquer instante, apenas um membro pode conter dados válidos. - Tamanho do Union: O tamanho de um
unioné igual ao tamanho do seu maior membro. - Comportamento de Sobrescrita: Atribuir um valor a um membro sobrescreve os valores dos outros membros, devido ao compartilhamento de memória.
- Casos de Uso:
Unionssão úteis para economizar memória ou quando se lida com diferentes formatos de dados que não são usados simultaneamente. A ordem dos membros na declaração não afeta o tamanho total ou o comportamento básico de compartilhamento de memória.