Choose Appropriate Data Layout for Struct/Tuple/Enum

2026-08-30 浏览 (1)


id: mem-01 original_id: P.UNS.MEM.01 level: P impact: HIGH

Choose Appropriate Data Layout for Struct/Tuple/Enum

Summary

Use #[repr(...)] attributes to control data layout when interfacing with C, doing memory mapping, or needing specific guarantees.

Rationale

Rust's default layout is unspecified and may change between compiler versions. For FFI, persistence, or low-level memory operations, you need predictable layout.

Repr Attributes

AttributeUse Case
#[repr(C)]C-compatible layout, stable field order
#[repr(transparent)]Single-field struct with same layout as field
#[repr(packed)]No padding (alignment = 1), careful with references!
#[repr(align(N))]Minimum alignment of N bytes
#[repr(u8)], #[repr(i32)], etc.Enum discriminant type

Bad Example

// DON'T: Assume Rust struct layout matches C
struct BadFFI {
    a: u8,
    b: u32,
    c: u8,
}
// Rust may reorder fields or add different padding than C

// DON'T: Use packed without understanding the risks
#[repr(packed)]
struct Dangerous {
    a: u8,
    b: u32,
}

fn bad_ref(d: &Dangerous) -> &u32 {
    &d.b  // UB: Creates unaligned reference!
}

Good Example

// DO: Use repr(C) for FFI
#[repr(C)]
struct GoodFFI {
    a: u8,
    b: u32,
    c: u8,
}
// Guaranteed: a at 0, padding 1-3, b at 4, c at 8, padding 9-11

// DO: Use repr(transparent) for newtypes
#[repr(transparent)]
struct Wrapper(u32);
// Guaranteed same layout as u32, can be transmuted

// DO: Use repr(packed) carefully, access via copy
#[repr(C, packed)]
struct PackedData {
    header: u8,
    value: u32,
}

impl PackedData {
    fn value(&self) -> u32 {
        // Copy out the value to avoid unaligned reference
        let ptr = std::ptr::addr_of!(self.value);
        // SAFETY: Reading unaligned is OK with read_unaligned
        unsafe { ptr.read_unaligned() }
    }
}

// DO: Use align for SIMD or cache line alignment
#[repr(C, align(64))]
struct CacheAligned {
    data: [u8; 64],
}

// DO: Specify enum discriminant for FFI
#[repr(u8)]
enum Status {
    Ok = 0,
    Error = 1,
    Unknown = 255,
}

Layout Guarantees

use std::mem::{size_of, align_of};

#[repr(C)]
struct Example {
    a: u8,   // offset 0, size 1
    // padding: 3 bytes
    b: u32,  // offset 4, size 4
    c: u8,   // offset 8, size 1
    // padding: 3 bytes
}

assert_eq!(size_of::<Example>(), 12);
assert_eq!(align_of::<Example>(), 4);

// repr(Rust) might reorder to: b, a, c -> size 8

Checklist

  • Is this type used in FFI? → Use #[repr(C)]
  • Is this a newtype wrapper? → Consider #[repr(transparent)]
  • Do I need specific alignment? → Use #[repr(align(N))]
  • Am I using packed? → Never create references to packed fields

Related Rules

  • ffi-13: Ensure consistent data layout for custom types
  • ffi-14: Types in FFI should have stable layout
  • ptr-04: Alignment considerations

你可能感兴趣的文章

Do Not Expose Raw Pointers in Public APIs

Unsafe Code Authors Must Verify Safety Invariants

Ensure Consistent Data Layout for Custom Types

Add Safety Section in Docs for Public Unsafe Functions

Do Not Use Union Variants Across Different Lifetimes

Use MaybeUninit for Uninitialized Memory

Ensure C-ABI Compatibility for Strings Between Rust and C

Do Not Dereference Pointers Cast to Misaligned Types

Use Dedicated Opaque Type Pointers Instead of c_void for C Opaque Types

Handle Errors Properly in FFI

  • 所属分类: AI
  • 本文标签: rust
  • 版权声明: 本文链接 https://seaxiang.com/blog/ptUZss4W