解决Rust FFI中的联合结构

时间:2014-11-03 08:46:02

标签: rust unions xlib ffi

解决c-union结构XEvent时遇到问题。

我在Rust中尝试使用Xlib和X Record Extension。我用rust-bindgen生成ffi绑定。所有代码都托管在github上alxkolm/rust-xlib-record

当我尝试从XEvent结构中提取数据时,行src/main.rs:106上发生了故障。


let key_event: *mut xlib::XKeyEvent = event.xkey();
println!("KeyPress {}", (*key_event).keycode); // this always print 128 on any key

我的程序会听取关键事件并打印出keycode。但是我按下的任何按键总是128。我认为这是从C union类型到Rust类型的错误转换。

XEvent的定义从这里开始src/xlib.rs:1143。它是c-union。原始C定义here

GitHub中的代码可以通过cargo run命令运行。它编译时没有错误。

我做错了什么?

1 个答案:

答案 0 :(得分:4)

请注意rustbindgen生成与C union的绑定,其安全性与C相同;因此,在致电时:

event.xkey(); // gets the C union 'xkey' field

没有运行时检查xkey是当前包含值的字段。

这是因为C没有标记union(即union知道当前正在使用哪个字段),开发人员想出了各种编码这些信息的方法(*),我知道的两个是:

  • 外部供应商;通常是union
  • 之前的结构的另一个字段
  • union
  • 中每个结构的第一个字段

在这里,你处于后一种情况int type;是联合的第一个字段,每个嵌套结构都以int _type;开头,表示这一点。因此,您需要采用两步法:

  1. 咨询type()
  2. 取决于值,请调用正确的重新解释
  3. 从类型值到正在使用的实际字段的映射应该是C库文档的一部分,希望如此。

    我邀请你想出一个围绕这个低级别union的包装器,它将使检索结果更安全。至少,您可以检查它是访问者中的正确类型;完整的方法是提出一个Rust enum,它将代理包装到所有字段并允许模式匹配。

    (*)实际上有时会完全忽略它,例如在C99中重新解释floatint可以使用union { float f; int i; }