How can I get the offset of a field in a repr(C) struct as a constant?

FWIW, although ::memoffset is currently the best effort to get the offset for #[repr(C)] structs that come from external crates, its implementation is technically UB, so if the definition comes from your own crate, you should take advantage of that to get offsets without unsafe and thus without UB:

#![forbid(unsafe_code)]

// ...

with_offsets! {
    #[repr(C)]
    pub
    struct Example {
        #[offset(FOO_OFFSET)]
        foo: u32,

        #[offset(BAR_OFFSET)]
        bar: usize,
    }
}

fn main ()
{
    dbg!(Example::BAR_OFFSET); // outputs 8 on the Playground
}

which, with #[macro_rules_attribute], leads to:

#[macro_use]
extern crate macro_rules_attribute;

#[macro_rules_attribute(with_offsets!)]
#[repr(C)]
pub
struct Example {
    #[offset(FOO_OFFSET)]
    foo: u32,

    #[offset(BAR_OFFSET)]
    bar: usize,
}

EDIT: and here is a version not requiring special identifiers for the constants:

#![forbid(unsafe_code)]

// ...

with_offsets! {
    #[repr(C)]
    pub
    struct Example {
        foo: u32,
        _pad: u8,
        baz: u8,
        bar: u64,
    }
}

fn main ()
{
    assert_eq!(0, dbg!(Example::offset_to.foo));
    assert_eq!(5, dbg!(Example::offset_to.baz));
    assert_eq!(8, dbg!(Example::offset_to.bar));
}
3 Likes