首页 文章

解决Rust FFI中的联合结构

提问于
浏览
5

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

我用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 回答

  • 4

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

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

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

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

    • 外部供应商;通常在 union 之前的另一个结构领域

    • union 中每个结构的第一个字段

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

    • 咨询 type()

    • 取决于值,请调用正确的重新解释

    从类型值到正在使用的实际字段的映射应该是C库文档的一部分,希望如此 .

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

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

相关问题