Usando Uniões em C para Empacotamento e Desempacotamento Eficiente de Dados
Usando Uniões em C para Empacotamento e Desempacotamento Eficiente de Dados
Uniões fornecem uma maneira poderosa e eficiente em memória de reinterpretar os mesmos bytes como diferentes tipos de dados. Embora originalmente destinadas a memória compartilhada entre variáveis mutuamente exclusivas, programadores C modernos frequentemente usam uniões para empacotamento, desempacotamento e type punning – especialmente ao lidar com protocolos seriais ou comunicação de baixo nível.
Como uma União Compartilha Memória
Todos os membros de uma união compartilham a mesma região de memória. O maior membro determina o tamanho da união, e cada membro começa no mesmo endereço.
union { uint16_t word; struct { uint8_t byte1; uint8_t byte2; }; } u1;
Aqui, word ocupa dois bytes, enquanto a estrutura aninhada divide esses dois bytes em byte1 e byte2. O layout pode ser visualizado como:

Empacotando Dois Bytes em uma Palavra de 16 bits
Para combinar dois valores de 8 bits x e y em uma palavra de 16 bits, atribua-os aos membros da estrutura e então leia o membro word:
u1.byte1 = y; u1.byte2 = x; uint16_t packed = u1.word;
Este "type punning" é direto, mas depende da ordem de bytes do processador.
Endianness do Processador Importa
Sistemas little-endian armazenam o byte menos significativo primeiro, enquanto sistemas big-endian armazenam o byte mais significativo primeiro. Considere a sequência 0x01020304:

Executar um teste simples em uma máquina little-endian resulta em:
#include <stdio.h> #include <stdint.h> int main() { union { struct { uint8_t byte1; uint8_t byte2; }; uint16_t word; } u1; u1.byte1 = 0x21; u1.byte2 = 0x43; printf("Word is: %#X\n", u1.word); return 0; }
Saída: Word is: 0X4321 – confirmando armazenamento little-endian. Em um alvo big-endian, o mesmo código produziria 0X2143.
Alternativa Bitwise: Empacotamento Independente de Endianness
Deslocamento e máscara fornecem uma maneira portátil de construir um valor de 16 bits:
uint16_t word2 = (((uint16_t)byte3) << 8) | ((uint16_t)byte4);
Comparando ambos os métodos:
#include <stdio.h> #include <stdint.h> int main() { union { struct { uint8_t byte1; uint8_t byte2; }; uint16_t word1; } u1; u1.byte1 = 0x21; u1.byte2 = 0x43; printf("Word1 is: %#X\n", u1.word1); uint8_t byte3 = 0x21, byte4 = 0x43; uint16_t word2 = (((uint16_t)byte3) << 8) | ((uint16_t)byte4); printf("Word2 is: %#X\n", word2); return 0; }
Em um processador big-endian: Word1 is: 0X2143, Word2 is: 0X2143. Em um processador little-endian: Word1 is: 0X4321, Word2 is: 0X2143. A abordagem bitwise garante resultados consistentes entre arquiteturas.
Exemplo Prático: Enviando um Float via UART
Links seriais normalmente transmitem um byte por vez. Para enviar um float de 32 bits, podemos usar uma união para visualizar o float como um array de quatro bytes:
union buffer { float f; struct { uint8_t byte[4]; }; };
Lado transmissor:
union buffer tx; union buffer rx; float f1 = 5.5f; tx.f = f1; for (int i = 0; i < 4; ++i) { // send tx.byte[i] over UART rx.byte[i] = tx.byte[i]; // Simulated receive } printf("The received data is: %f\n", rx.f);
Saída: The received data is: 5.500000. A união separa limpa a representação em bytes do valor de ponto flutuante, tornando o código legível e de fácil manutenção.

Principais Conclusões
- Uniões permitem type punning, mas resultados dependem de endianness.
- Operadores bitwise fornecem empacotamento portável, independente de arquitetura.
- Para clareza e manutenção, muitos desenvolvedores ainda preferem uniões em contextos embarcados.
- Uniões brilham ao transmitir estruturas de dados arbitrárias sobre links orientados a bytes.
Para explorar mais sobre C, uniões e sistemas embarcados, navegue pela minha lista completa de artigos.
Integrado
- Semáforos no Nucleus RTOS: Serviços Utilitários e Estruturas de Dados
- Exército dos EUA Avança em Manutenção Baseada em Condição com Sensores Inovadores e Análise Preditiva
- Como IIoT e Análise de Dados Transformam EHS: Aumentando Segurança, Eficiência e Economia
- Construindo IA Responsável e Confiável: Guia para Explicabilidade, Responsabilidade e Ética
- Fog Computing Explicado: Transformando o Fluxo de Dados IoT e Reduzindo Carga na Nuvem
- Uniões em C Explicadas: Gerenciamento Eficiente de Memória para Múltiplos Tipos de Dados
- Visibilidade da Cadeia de Suprimentos: O Papel Crucial de Dados e Contexto
- Revolucionando a Gestão de Frotas: Integração de IA e IoT para Operações Mais Inteligentes
- AIoT Industrial: Unindo IA e IoT para Impulsionar a Inovação da Indústria 4.0
- Litmus e Oden Lançam Soluções IIoT Integradas para Manufatura Inteligente