由于内存布局问题,将带标签的C联合转换为Rust枚举时出现问题

时间:2019-01-29 19:14:37

标签: c rust

我正在尝试与如下结构的C事件API进行交互:

struct EventA {
    int type;
    int data1;
    int data2;
};

struct EventB {
    int type;
    int data1;
};

union Event {
    int type;
    EventA eventA;
    EventB eventB;
};

//grabs the next event from the queue.
void pollEvent(Event *event); 

在C API中,type字段用于确定发生了什么类型的事件。这本质上是一个标记的联合,或Rust中的枚举。我知道Rust允许您使用#[repr(type)]选择枚举的基础标签,但是我相信Rust不能保证该标签是枚举的第一个字段。 (还是它总是最后一个字段?)这在将API转换为Rust时有点麻烦,因为我需要某种类型的中间人结构来进行轮询,然后匹配其类型,将其转换为枚举,然后用户将与枚举。

如果我知道标记是枚举的第一个字段,则知道枚举和联合具有相同的内存表示形式,我可以将其作为指针传递。

我想做什么:

use::std::os::raw::c_int;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct EventA {
    pub data1: c_int,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct EventB {
    pub data1: c_int,
    pub data2: c_int,
}

#[repr(i32)] //I'm assuming c_int is 32 bit.
#[derive(Copy, Clone)]
pub enum Event {
    // <---- Put the tag is here, followed the union memory, 
    A(EventA),
    B(EventB),
}

extern {
    pub fn pollEvents(*mut Event);
}

pub fn poll_events(*mut Event) {
    unsafe {
        pollEvents(*mut Event);
    }
}

1 个答案:

答案 0 :(得分:0)

有一个RFC可以保证在基本上允许您想要的枚举的枚举上使用#[repr(C, Int)]时的布局。请注意,与往常一样,Rust只能做出最好的猜测,您应该在编译时为内存布局添加测试。