2014-11-03 125 views
5

解決c-union結構XEvent問題。在Rust中解決聯合結構FFI

我用的Xlib和X記錄擴展魯斯特試驗。我使用rust-bindgen生成了ffi綁定。所有代碼託管在github上alxkolm/rust-xlib-record

故障發生在線路src/main.rs:106當我嘗試從XEvent結構中提取數據。

 

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

我的節目聽重點事件並打印出keycode。但是在我按任何鍵時總是128。我認爲從C聯合類型到Rust類型的這種錯誤轉換。 XEvent的

定義從這裏開始src/xlib.rs:1143。這是C聯盟。原始C定義here。從GitHub

代碼可以通過cargo run命令運行。它的編譯沒有錯誤。

我做錯了什麼?

+0

您能否準確指出您遇到的錯誤?如果您有編譯時錯誤,那麼編譯器錯誤消息將會很有用;如果你有加載時間錯誤,那麼...或者是你總是得到'128'並且期待別的東西的問題? – 2014-11-03 13:33:11

+0

在任何按鍵上,我按下鍵碼總是128.它是完全可編譯的,沒有錯誤。修復問題的文本。 – alxkolm 2014-11-03 14:00:49

+1

你是否檢查過事件的類型是你期望的?生成的Rust代碼會盲目服從你:你要求'xkey'對應地解釋內存,但是如果它不是按鍵事件,而是別的東西,那麼它就沒有意義。 – 2014-11-03 15:13:48

回答

3

當心rustbindgen生成儘可能多的安全性與C結合至C union;其結果是,打電話時:

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

沒有運行時檢查xkey目前包含值的字段。

這是因爲由於C沒有標記union(即union知道哪個字段當前正在使用),所以開發人員提出了各種編碼這些信息的方法(*),我知道這兩個方法是:

  • 外部供應商;典型地union
  • 每個結構體在union

在此,第一場,則是在後者的情況下int type;前右側的結構的另一個字段是聯合的第一個字段,並且每個嵌套結構從int _type;開始表示這一點。因此,你需要兩步驟的方法:

  1. 諮詢type()
  2. 取決於值,調用正確的重新解釋

映射從類型的值,以現場實際是使用應該是C庫的文檔的一部分,希望。

我邀請你拿出一個圍繞這個低級union的包裝,這將使它更安全地檢索結果。至少,你可以檢查它是訪問器中的正確類型;完整的方法是想出一個Rust enum,它將代理包裝到所有字段並允許模式匹配。(*)並且實際上有時完全忽略它,例如在C99中重新解釋float作爲int可以使用union { float f; int i; }可以使用。