30

据我所知,Rust 编译器允许对结构的每个字段进行打包、重新排序和添加填充。如果需要,如何指定精确的内存布局?

在 C# 中,我有StructLayout属性,而在 C/C++ 中,我可以使用各种编译器扩展。我可以通过检查预期值位置的字节偏移来验证内存布局。

我想编写使用自定义着色器的 OpenGL 代码,这需要精确的内存布局。有没有办法在不牺牲性能的情况下做到这一点?

4

3 回答 3

36

FFI 指南中所述,您可以向结构添加属性以使用与 C 相同的布局:

#[repr(C)]
struct Object {
    a: i32,
    // other members
}

而且您还可以打包结构:

#[repr(C, packed)]
struct Object {
    a: i32,
    // other members
}

为了检测内存布局是否正常,您可以初始化一个结构并通过将指针转换为整数来检查偏移量是否正常:

#[repr(C, packed)]
struct Object {
    a: u8,
    b: u16,
    c: u32, // other members
}

fn main() {
    let obj = Object {
        a: 0xaa,
        b: 0xbbbb,
        c: 0xcccccccc,
    };
    let a_ptr: *const u8 = &obj.a;
    let b_ptr: *const u16 = &obj.b;
    let c_ptr: *const u32 = &obj.c;

    let base = a_ptr as usize;

    println!("a: {}", a_ptr as usize - base);
    println!("b: {}", b_ptr as usize - base);
    println!("c: {}", c_ptr as usize - base);
}

输出:

a: 0
b: 1
c: 3
于 2014-10-09T06:30:57.183 回答
5

没有了to_uint。在 Rust 1.0 中,代码可以是:

#[repr(C, packed)]
struct Object {
    a: i8,
    b: i16,
    c: i32, // other members
}

fn main() {
    let obj = Object {
        a: 0x1a,
        b: 0x1bbb,
        c: 0x1ccccccc,
    };

    let base = &obj as *const _ as usize;
    let a_off = &obj.a as *const _ as usize - base;
    let b_off = &obj.b as *const _ as usize - base;
    let c_off = &obj.c as *const _ as usize - base;

    println!("a: {}", a_off);
    println!("b: {}", b_off);
    println!("c: {}", c_off);
}
于 2015-09-19T10:50:22.953 回答
1

enum您还可以像这样为“数据承载”设置内存布局。

#[repr(Int)]
enum MyEnum {
    A(u32),
    B(f32, u64),
    C { x: u32, y: u8 },
    D,
}

详细信息在手册和 RFC2195 中进行了描述。

于 2019-11-21T15:45:42.307 回答