⚡ Cap 16: Structs, Struct Padding, Unions e Enumerações
Bem-vindo ao décimo sexto capítulo da Especialização em Engenharia de Sistemas com Linguagem C (C17/C23)! ⚡
Na Engenharia de Software e de Sistemas, quase nunca trabalhamos apenas com tipos primitivos soltos. Precisamos modelar entidades complexas do mundo real: cabeçalhos de pacotes TCP/IP, registros de banco de dados, nós de árvores e descritores de dispositivos de hardware. Neste capítulo, você dominará os Tipos Compostos Heterogêneos (struct), a mecânica de alinhamento de hardware (Struct Padding), o compartilhamento de memória com union, a semântica de enum e os Campos de Bits (Bit-fields).
🗺️ Mapa Conceitual do Capítulo
graph TD
A["Tipos Compostos em C"] --> B["1. Estruturas (struct & typedef)"]
A --> C["2. Alinhamento & Struct Padding"]
A --> D["3. Uniões de Memória (union)"]
A --> E["4. Enumerações e Bit-Fields"]
B --> B1["Operador Ponto (.) vs Seta (->) com ponteiros"]
C --> C1["Alinhamento de Barramento de Memória da CPU"]
D --> D1["Campos sobrepostos compartilhando o mesmo Byte 0"]
E --> E1["enum para códigos limpos e unsigned int f : 1 para bits"]
🏛️ 1. Estruturas Heterogêneas (struct) e typedef
Uma struct agrupa variáveis de tipos diferentes sob um único bloco contíguo de memória:
#include <stdio.h>
#include <stdint.h>
// Definição idiomática com typedef
typedef struct {
uint32_t id;
char nome[32];
double tensaoVolts;
bool operacional;
} SensorIndustrial;
int main(void) {
// 1. Inicialização direta
SensorIndustrial s1 = {101, "Termopar_Forno", 3.28, true};
// 2. Acesso direto com operador ponto (.)
printf("Sensor #%u: %s (%.2lf V)\n", s1.id, s1.nome, s1.tensaoVolts);
// 3. Acesso por ponteiro com operador seta (->)
SensorIndustrial *ptr = &s1;
ptr->tensaoVolts = 3.35; // Equivalente a (*ptr).tensaoVolts = 3.35;
return 0;
}
📐 2. Alinhamento de Memória de Hardware e Struct Padding
A CPU lê a memória RAM em palavras de 4 bytes (32 bits) ou 8 bytes (64 bits). Para otimizar os ciclos de clock do barramento de dados, o compilador insere bytes de enchimento vazios (Padding) entre os membros da estrutura.
Exemplo de Impacto do Padding no Tamanho Total:
// ❌ Estrutura Desordenada (Gasta 24 Bytes na RAM):
struct Desordenada {
char a; // 1 Byte + 7 Bytes de PADDING
double b; // 8 Bytes
char c; // 1 Byte + 7 Bytes de PADDING
}; // sizeof = 24 Bytes!
// ✅ Estrutura Otimizada por Tamanho Decrescente (Gasta 16 Bytes na RAM):
struct Otimizada {
double b; // 8 Bytes
char a; // 1 Byte
char c; // 1 Byte + 6 Bytes de PADDING no final
}; // sizeof = 16 Bytes! (Economia de 33% de memória!)
[!TIP] Regra de Ouro de Otimização: Ordene os membros da sua
structdo maior tipo para o menor (double$\rightarrow$int$\rightarrow$short$\rightarrow$char) para minimizar o padding inserido pelo compilador.
🧬 3. Uniões de Memória Compartilhada (union)
Uma union armazena múltiplos campos no mesmo endereço físico de memória. O tamanho total da união é exatamente o tamanho do seu maior membro:
typedef union {
uint32_t valorInteiro; // 4 Bytes
uint8_t bytes[4]; // 4 Bytes individuais
} ConversorRegistrador;
int main(void) {
ConversorRegistrador reg;
reg.valorInteiro = 0x12345678;
// Em arquiteturas Little-Endian (x86/ARM), os bytes são lidos em ordem inversa:
printf("Byte 0: 0x%02X\n", reg.bytes[0]); // 0x78
printf("Byte 3: 0x%02X\n", reg.bytes[3]); // 0x12
return 0;
}
🏷️ 4. Enumerações (enum) e Campos de Bits (Bit-Fields)
1. Enumerações Fortes (enum):
Eliminam “números mágicos” e documentam estados do sistema:
typedef enum {
ESTADO_OFFLINE = 0,
ESTADO_CONECTANDO = 1,
ESTADO_ONLINE = 2,
ESTADO_ERRO_CRITICO = 99
} EstadoRede;
2. Campos de Bits (Bit-Fields):
Permitem empacotar múltiplos flags booleanos no nível de bits individuais:
typedef struct {
unsigned int habilitado : 1; // Ocupa exatamente 1 BIT (0 ou 1)
unsigned int modoLeitura : 1; // 1 BIT
unsigned int nivelAlarme : 2; // 2 BITS (0 a 3)
unsigned int codigoErro : 4; // 4 BITS (0 a 15)
} RegistradorHardware; // Ocupa apenas 1 Byte / 4 Bytes em vez de 4 inteiros!
🔍 5. Diagnóstico & Resolução de Problemas (Troubleshooting)
| Sintoma Observado | Causa Provável | Como Resolver |
|---|---|---|
sizeof(MinhaStruct) é maior que a soma manual dos seus campos |
O compilador inseriu bytes de Struct Padding para alinhamento de barramento. | Reordene os campos do maior para o menor ou use a diretiva de empacotamento __attribute__((packed)). |
Erro de compilação: request for member in something not a structure or union |
Uso do operador ponto . em um ponteiro de estrutura em vez da seta ->. |
Utilize o operador seta: ptr->campo. |
Ao gravar em um campo da union, o outro campo foi corrompido |
Os campos de uma union compartilham a mesma memória física. |
Lembre-se de que apenas um membro da união pode ser válido por vez. |
🏆 6. Desafio Prático de Consolidação
Enunciado do Desafio:
Desenvolva um programa em C chamado parser_pacote_telemetria.c:
- Crie uma
enum TipoComando { CMD_PING = 1, CMD_LEITURA = 2, CMD_REINICIAR = 3 };. - Crie uma
union CargaUtilcontendo:float temperatura;euint32_t codigoRaw;. - Crie a
struct PacoteRedecontendo:uint8_t idOrigem;uint8_t idDestino;TipoComando comando;CargaUtil payload;
- Crie a função
void processarPacote(const PacoteRede *pacote);que imprima os campos e o tamanho total da estrutura (sizeof) em bytes.
🔍 Ver Solução Comentada do Desafio
#include <stdio.h>
#include <stdint.h>
typedef enum {
CMD_PING = 1,
CMD_LEITURA = 2,
CMD_REINICIAR = 3
} TipoComando;
typedef union {
float temperatura;
uint32_t codigoRaw;
} CargaUtil;
typedef struct {
uint8_t idOrigem;
uint8_t idDestino;
TipoComando comando;
CargaUtil payload;
} PacoteRede;
void processarPacote(const PacoteRede *pacote) {
printf("Pacote: Origem #%u -> Destino #%u | Cmd: %d | Temp: %.2lf C\n",
pacote->idOrigem, pacote->idDestino, pacote->comando, pacote->payload.temperatura);
printf("Tamanho em memoria (sizeof): %zu bytes\n", sizeof(PacoteRede));
}
int main(void) {
PacoteRede pkt = {
.idOrigem = 1,
.idDestino = 100,
.comando = CMD_LEITURA,
.payload = { .temperatura = 23.75f }
};
processarPacote(&pkt);
return 0;
}
🧭 Navegação Rápida
| 📖 Teoria | 📊 Slides | 🧠 Quiz | 💻 Exemplos | 🧩 Exercícios | | :— | :— | :— | :— | :— | | Ler Teoria | Ver Slides | Fazer Quiz | Ver Exemplos | Praticar Exercícios |
🧭 Navegação do Capítulo: ⬅️ Capítulo Anterior · 📚 Sumário do Módulo · ➡️ Próximo Capítulo