2

我正在尝试在 Rust 中为 FFI 重新创建一个混合位域成员和“普通”成员的 C 结构。

我已经读到bitflags crate将是一个可以使用的,不幸的是我发现文档缺乏关于语法实际如何工作的文档。

bitflags crate 可以更轻松地创建与 C 中使用枚举类似的样式的位掩码。位域板条箱声称创建可以访问的位域,但是我不知道它是如何工作的。

我有一个这样的C结构:

struct mixed {
    unsigned int flag_1_1 : 1;
    unsigned int flag_2_7 : 7;
    unsigned int flag_3_8 : 8;

    unsigned int some_val1;
    unsigned int some_val2;

    unsigned int flag_4_16 : 16;
};

我不知道如何在 Rust 中表示它,我会使用 crate libc来访问c_uint,但除此之外,我目前几乎没有想法,并且找到其他未证明成功的代码:

#[repr(transparent)] // do I also need repr(C) ?
struct mixed {
    flags_1_3: mixed_flags_1_3;
    some_val1: c_uint;
    some_val2: c_uint;
    flags_4: mixed_flags_4;
}

bitfield!(
    #[repr(transparent)] // do I also need repr(C), here too?
    struct mixed_flags_1_3(u16 /* what about this parameter? */) {
        u8; // what does this mean?
        /* get/field, set: first bit, last bit; */
        flag_1_1, _: 0, 0;
        flag_2_7, _: 7, 1;
        flag_3_8, _: 15, 8;
    }
)

bitfield!(
    #[repr(transparent)]
    struct mixed_flags_4(u8) {
        u8;
        flag_4_16, _: 15, 0;
    }
)

这些只是猜测,如何创建正确的表示?

4

2 回答 2

1

在这种情况下,您可以通过bindgen查看生成的代码:

$ bindgen test.h

#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<Storage, Align>
where
    Storage: AsRef<[u8]> + AsMut<[u8]>,
{
    storage: Storage,
    align: [Align; 0],
}

//skipped code with access method for bit fields 

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct mixed {
    pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize], u8>,
    pub some_val1: ::std::os::raw::c_uint,
    pub some_val2: ::std::os::raw::c_uint,
    pub _bitfield_2: __BindgenBitfieldUnit<[u8; 2usize], u16>,
    pub __bindgen_padding_0: u16,
}
于 2018-03-09T12:44:33.647 回答
0

使用rustc -- -Z unstable-options --pretty=expanded我想我可以弄清楚宏确实如此,这似乎产生了一些可能是正确的东西,但是这可能仅在编译器不尝试填充或重新排序结构中的位域时才兼容。

#[repr(transparent)] // do I also need repr(C) ?
struct mixed {
    flags_1_3: mixed_flags_1_3;
    some_val1: c_uint;
    some_val2: c_uint;
    flags_4: mixed_flags_4;
}

bitfield!(
    #[repr(transparent)] // do I also need repr(C), here too?
    //  Results in a "tuple struct", ie. u16 = total size of bitfields
    struct mixed_flags_1_3(u16) {
        // All the following fields value should be treated as an
        // unsigned int when accessed
        c_uint;
        /* get/field, set: first bit, last bit; */
        flag_1_1, _: 0, 0;
        flag_2_7, _: 7, 1;
        // One could change the type again here, if one wanted to:
        // u16
        flag_3_8, _: 15, 8;
    }
)

bitfield!(
    #[repr(transparent)]
    struct mixed_flags_4(u16) {
        c_uint;
        flag_4_16, _: 15, 0;
    }
)

但至少现在我认为我将只使用 libclang 和 bindgen 作为依赖项并自动生成我的绑定,因为上述平台兼容性问题。

于 2018-03-09T17:35:43.317 回答