解决Rust FFI中的联合结构

alx*_*olm 5 ffi xlib unions rust

我有解决c-union结构XEvent的问题.

我在Rust中试验Xlib和X Record Extension.我用rust-bindgen生成ffi-bindings .所有代码都托管在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定义在这里.

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

我做错了什么?

Mat*_* M. 4

请注意,rustbindgen生成与 C 的绑定union与在 C 中一样安全;结果,当调用时:

event.xkey(); // gets the C union 'xkey' field
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  1. 咨询type()
  2. 根据值,调用正确的重新解释

希望从类型值到实际使用字段的映射应该成为 C 库文档的一部分。

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

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