---
title: "Packed Struct Layout — Como Resolver em Zig"
url: "https://ziglang.com.br/erros/packed-struct-layout-como-resolver-em-zig/"
markdown_url: "https://ziglang.com.br/erros/packed-struct-layout-como-resolver-em-zig.MD"
description: "Entenda os problemas de layout em packed structs em Zig. Veja limitações, erros comuns e como trabalhar corretamente com structs compactas."
date: "2026-02-21"
author: "Zig Brasil"
---

# Packed Struct Layout — Como Resolver em Zig

Entenda os problemas de layout em packed structs em Zig. Veja limitações, erros comuns e como trabalhar corretamente com structs compactas.


# Packed Struct Layout — Como Resolver em Zig

## O Que Este Erro Significa

Problemas com packed structs em Zig ocorrem quando o programador não respeita as restrições especiais desse tipo de struct. Uma `packed struct` em Zig armazena seus campos em um layout compacto, sem padding entre campos e com bit-packing. Isso é útil para protocolos de rede, hardware e formatos binários, mas vem com limitações.

Mensagens de erro comuns:

```
error: packed structs cannot contain fields of type '[]const u8'
```

```
error: pointer to packed struct field has non-standard alignment
```

```
error: cannot take address of packed struct field
```

## Causas Comuns

### 1. Campos com Tipos Proibidos em Packed Struct

```zig
const Pacote = packed struct {
    tipo: u8,
    dados: []const u8, // ERRO: slices não são permitidos em packed struct
};
```

### 2. Tentar Obter Ponteiro para Campo de Packed Struct

```zig
const Registrador = packed struct {
    bit_a: u1,
    bit_b: u1,
    valor: u6,
};

pub fn main() void {
    var reg = Registrador{ .bit_a = 1, .bit_b = 0, .valor = 30 };
    const ptr = &reg.valor; // ERRO: não pode obter ponteiro para campo sub-byte
    _ = ptr;
}
```

### 3. Campos de Struct Regular dentro de Packed

```zig
const Inner = struct { // struct regular com padding
    x: u32,
    y: u8,
};

const Outer = packed struct {
    cabecalho: u8,
    dados: Inner, // ERRO: struct regular dentro de packed
};
```

### 4. Campos com Alinhamento Especial

```zig
const Pacote = packed struct {
    versao: u4,
    tipo: u4,
    dados: [100]u8, // ERRO: arrays grandes em packed struct
};
```

### 5. Usar Optional ou Error Union em Packed

```zig
const Estado = packed struct {
    ativo: bool,
    valor: ?u8, // ERRO: optional não é permitido em packed struct
};
```

## Como Corrigir

### Solucao 1: Usar Apenas Tipos de Tamanho Fixo

```zig
const Pacote = packed struct {
    versao: u4,    // 4 bits
    tipo: u4,      // 4 bits
    flags: u8,     // 8 bits
    tamanho: u16,  // 16 bits
    // Total: 32 bits = 4 bytes
};

pub fn main() void {
    const p = Pacote{
        .versao = 1,
        .tipo = 3,
        .flags = 0xFF,
        .tamanho = 1024,
    };
    _ = p;
}
```

### Solucao 2: Packed Struct dentro de Packed

```zig
const Flags = packed struct {
    leitura: bool,    // 1 bit
    escrita: bool,    // 1 bit
    execucao: bool,   // 1 bit
    _reservado: u5,   // 5 bits para completar 1 byte
};

const Cabecalho = packed struct {
    tipo: u8,
    flags: Flags,   // OK: packed struct dentro de packed
    tamanho: u16,
};

pub fn main() void {
    const cab = Cabecalho{
        .tipo = 1,
        .flags = .{ .leitura = true, .escrita = false, .execucao = true, ._reservado = 0 },
        .tamanho = 256,
    };
    std.debug.print("Tamanho da struct: {} bytes\n", .{@sizeOf(Cabecalho)});
    _ = cab;
}

const std = @import("std");
```

### Solucao 3: Acessar Campos sem Ponteiro

```zig
const Registrador = packed struct {
    bit_a: u1,
    bit_b: u1,
    valor: u6,
};

pub fn main() void {
    var reg = Registrador{ .bit_a = 1, .bit_b = 0, .valor = 30 };

    // ERRADO: &reg.valor — ponteiro para campo sub-byte
    // CORRETO: ler e escrever diretamente
    const v = reg.valor;  // Lê o campo
    reg.valor = v + 1;    // Escreve no campo
    _ = reg;
}
```

### Solucao 4: Converter entre Packed Struct e Inteiro

```zig
const Flags = packed struct {
    bit0: u1,
    bit1: u1,
    bit2: u1,
    bit3: u1,
    upper: u4,
};

pub fn main() void {
    // De inteiro para packed struct
    const raw: u8 = 0b1010_0101;
    const flags: Flags = @bitCast(raw);
    _ = flags;

    // De packed struct para inteiro
    const f = Flags{ .bit0 = 1, .bit1 = 0, .bit2 = 1, .bit3 = 0, .upper = 0xA };
    const byte: u8 = @bitCast(f);
    _ = byte;
}
```

### Solucao 5: Usar extern struct Quando Precisa de Ponteiros

```zig
// Quando precisa de ponteiros para campos, use extern struct
const PacoteExtern = extern struct {
    tipo: u32,
    tamanho: u32,
    flags: u32,
};

pub fn main() void {
    var pac = PacoteExtern{ .tipo = 1, .tamanho = 100, .flags = 0 };
    const ptr_tipo = &pac.tipo; // OK: campos de extern struct são endereçáveis
    ptr_tipo.* = 2;
    _ = pac;
}
```

### Solucao 6: Separar Dados Packed e Não-Packed

```zig
const std = @import("std");

// Packed para o cabeçalho binário
const CabecalhoBin = packed struct {
    versao: u4,
    tipo: u4,
    flags: u8,
    tamanho: u16,
};

// Regular para uso interno
const Pacote = struct {
    cabecalho: CabecalhoBin,
    dados: []const u8, // Slice é OK em struct regular
    allocator: std.mem.Allocator,

    fn fromBytes(bytes: []const u8, allocator: std.mem.Allocator) !Pacote {
        if (bytes.len < @sizeOf(CabecalhoBin)) return error.DadosInsuficientes;
        const cab: CabecalhoBin = @bitCast(bytes[0..@sizeOf(CabecalhoBin)].*);
        return .{
            .cabecalho = cab,
            .dados = bytes[@sizeOf(CabecalhoBin)..],
            .allocator = allocator,
        };
    }
};
```

## Packed vs Extern vs Regular

| Propriedade | `struct` | `extern struct` | `packed struct` |
|-------------|----------|----------------|-----------------|
| Padding | Sim (Zig decide) | Segue ABI C | Nenhum |
| Ponteiro para campo | Sim | Sim | Limitado |
| Bit fields | Não | Não | Sim |
| Slices/Optionals | Sim | Não | Não |
| Uso típico | Código Zig | FFI com C | Hardware/protocolos |

## Tamanho de Packed Struct

```zig
const std = @import("std");

const Exemplo = packed struct {
    a: u3,   // 3 bits
    b: u5,   // 5 bits
    c: u8,   // 8 bits
    d: u16,  // 16 bits
    // Total: 32 bits = 4 bytes
};

pub fn main() void {
    std.debug.print("Tamanho: {} bytes\n", .{@sizeOf(Exemplo)}); // 4
    std.debug.print("Bits: {}\n", .{@bitSizeOf(Exemplo)});       // 32
}
```

## Erros Relacionados

- [Pointer cast alignment](/erros/erro-pointer-cast-alignment/) — Alinhamento de ponteiro
- [Type coercion failed](/erros/erro-coercion-failed/) — Falha na coerção de tipos
- [@cImport failed](/erros/erro-c-import-failed/) — Problemas com struct C

## Links Úteis

- [Documentação oficial do Zig — packed struct](https://ziglang.org/documentation/master/#packed-struct)
- [Documentação oficial do Zig — extern struct](https://ziglang.org/documentation/master/#extern-struct)
- [Receitas de manipulação binária](/receitas/)
- [Tutorial sobre structs em Zig](/tutoriais/)
