CodeBlanks Logo Icon CodeBlanks

#[repr(C)] and #[repr(Rust)]

Learn the difference between #[repr(C)] and #[repr(Rust)].

#[repr(C)] and #[repr(Rust)]

repr attributes set an explicit contract on the layout:

  • repr(Rust): the default; the compiler is free.
  • repr(C): C-compatible, field order kept.
  • repr(u8)/repr(i32): fixes an enum's discriminant type.
  • repr(transparent): guarantees a single-field wrapper has the same ABI as the inner type.
  • repr(packed)/repr(align(n)): remove padding or raise the alignment.
#[repr(u8)]
enum Renk { Kirmizi = 1, Yesil = 2 }   // 1 byte

#[repr(transparent)]
struct Metre(f64);                       // same as f64

Which one when?

repr(C): FFI and binary formats. repr(u8): storing an enum as a byte or matching a C enum. repr(transparent): passing a newtype in place of the inner type in FFI. repr(align(64)): preventing two threads from sharing the same cache line (false sharing). repr(packed): only for mandatory binary layouts; it has a performance and safety cost.

#[repr(align(64))]
struct Sayac(std::sync::atomic::AtomicU64);   // each counter on its own cache line

Practice repr attributes

Define #[repr(u8)] enum Renk { Kirmizi = 1, Yesil = 2 } and #[repr(transparent)] struct Metre(f64);. Print size_of::<Renk>(), Renk::Yesil as u8 and size_of::<Metre>() separated by spaces.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
#![allow(dead_code)]
use std::mem::size_of;

#[repr(u8)]
enum Renk {
    Kirmizi = 1,
    Yesil = 2,
}

#[repr(transparent)]
struct Metre(f64);

fn main() {
    println!("{} {} {}", size_of::<Renk>(), Renk::Yesil as u8, size_of::<Metre>());
}

Expected output

1 2 8

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Why is taking a reference to a field of a <code>repr(packed)</code> struct a problem?

  • It isn't a problem
  • The size changes
  • The field may be unaligned; an unaligned reference is undefined behaviour Correct answer
  • The fields are private

Explanation: That's why the compiler treats references to packed fields as an error; the value is read by copying, or with addr_of! and read_unaligned.

2 Transparent wrapper

Question
#[repr(____)]
struct Metre(f64);
Answer
#[repr(transparent)]
struct Metre(f64);

Explanation: repr(transparent) makes the wrapper have the same ABI as the inner type.

3 repr and effect

Term Meaning
repr(C) C-compatible layout
repr(u8) 1-byte discriminant
repr(transparent) Same ABI as inner type
repr(align(64)) 64-byte alignment

All lessons in Expert