2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rust-bindgenでCヘッダを変換した後のunsafe操作メモ

Last updated at Posted at 2022-08-18

すごいぞbindgen

rust-bindgenというツールを使うとC言語の.hファイルからバインディングを自動生成してくれます!すごく便利ですね!

今回はbindgenで変換した後のお話です。私がCに疎いので間違えた解釈をしていることもあるかもしれませんが、C向けAPIでよくあるパターンとその対処法を書いていきます。

NULLポインタを用意する

let nullpo: *mut std::ffi::c_void = std::ptr::null_mut();

ハンドル生成でお世話になる。ポインタはasでキャストすることもできるみたいです。

目的データのポインタからデータをコピーする

let mut buf = vec![0; length];
let p_buf = buf.as_mut_ptr();
std::ptr::copy_nonoverlapping(p_src, p_buf, length);

Cのmemcpyと一緒。引数の順番は違う。セグフォの原因だいたいこいつ
コピー元がCの世界出身であれば正しくメモリ開放しましょう。

大きな構造体のメモリを初期化せずに確保する

let mut some_big_struct: MaybeUninit<SomeBigStruct> = MaybeUninit::uninit();
//ポインタを得る。
let p_some_big_struct = some_big_struct.as_mut_ptr();

初期化にかかる時間すらもったいない人向けです。
MaybeUninitは未初期化の変数にアクセスできないように包んでくれます。

Cstringを作る

let cstr = CString::new("string").unwrap();
let p_cstr = cstr.as_ptr();

これに限らず、as_ptr系のメソッドを使うときはそれが指す領域が存在していないとセグフォします。
ワンライナー癖のある人はポインタだけ生成しないように注意!

参考:

ライブラリをリンクする

build.rs
fn main(){println!(r"cargo:rustc-link-lib=dylib=path/to/library")}

ビルドスクリプトを書きます。
パスに.libなどの拡張子は必要ない。(多分.dllだったり.soだったりの拡張子を無視して扱えるすごいシステム)

共用体を使う

#[repr(C)]
#[derive(Copy, Clone)]
union MyUnion {
    f1: u32,
    f2: f32,
}

そもそも共用体の中身はCopy可能でなけらばならないのでCopyトレイトはつけるだけお得。
存在自体がtransmute系のunsafeなので可能な限り使いたくない。

おわりに

他にもあったら追加します。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?