---
title: C ABI と bindgen
url: https://doc.liz6.com/ja/rust/11-ffi-and-system-interaction/01-c-abi-and-bindgen
locale: ja
area: rust
tags:
- rust
- ffi-and-system-interaction
date: null
modified: 2026-07-16
description: C ABI と bindgen Rust から C を呼び出す第一步は、型レイアウトを一致させることです。repr(C) は Rust の struct が C ABI に従ってフィールドを配置し、C ヘッダ内の構造体とバイト単位でアラインメントされることを強制します。bindgen は C ヘッダから対応する Rus…
---

# C ABI と bindgen

> Rust から C を呼び出す第一步は、型レイアウトを一致させることです。`repr(C)` は Rust の struct が C ABI に従ってフィールドを配置し、C ヘッダ内の構造体とバイト単位でアラインメントされることを強制します。bindgen は C ヘッダから対応する Rust 型と関数シグネチャを自動生成し、手動で Rust/C の型マッピングを維持する退屈さとエラーを自動化します。callback の安全性の核心は、C から Rust へのコールバック時に panic が FFI 境界を越えて unwind してはならないという点にあります。

## C ↔ Rust 型マッピング

FFI における型の対応は自動的ではありません。`std::os::raw` または `libc` クレート内の C 互換型を明示的に使用する必要があります。

| C 型 | Rust 型 (libc) | 注意 |
|--------|-----------------|------|
| `int` | `c_int` (i32) | |
| `long` | `c_long` | Windows では 32-bit、Linux では 64-bit！ |
| `size_t` | `usize` | |
| `char *` (文字列) | `*const c_char` → `CStr::from_ptr()` | |
| `void *` | `*mut c_void` | |
| 構造体ポインタ (opaque) | `*mut MyStruct` | 間接参照せず、渡すのみ |
| enum | `#[repr(C)] enum` | C の enum は c_int サイズ |

重要な罠：`long` のサイズは LLP64 (Windows) では 4 バイト、LP64 (Linux) では 8 バイトです。C コードが `long` を 8 バイトとして依存している場合、Windows では `i64` を代わりに使用してください。

## bindgen による自動化

bindgen は C ヘッダから Rust の外部関数宣言、構造体、定数を自動生成します。

```rust
// build.rs
fn main() {
    println!("cargo:rerun-if-changed=wrapper.h");

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .allowlist_function("my_lib_.*")     // これらの関数のみバインド
        .allowlist_type("MyStruct")          // これらの型のみのバインド
        .generate()
        .expect("Unable to generate bindings");

    bindings.write_to_file(
        std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap())
            .join("bindings.rs"),
    ).expect("Couldn't write bindings");
}

// src/lib.rs
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
```

bindgen が処理すること：基本型のマッピング、struct のアラインメント、ネストされた struct、関数ポインタ、条件付き定義。
処理できないこと：インライン関数 (Rust へ手動でポートが必要)、C++ テンプレート。

## Callback: C から Rust への安全な境界

```rust
extern "C" fn callback(x: i32) {
    println!("C called with {}", x);
}

unsafe { register_callback(callback as unsafe extern "C" fn(i32)); }
```

callback 内で panic が FFI 境界を越えて発生すると未定義動作 (UB) になります。Cargo.toml で `panic = "abort"` を設定することは、このリスクを回避する最も直接的な方法です。unwinding を維持する必要がある場合は、callback 内のすべてのロジックを `catch_unwind` でラップしてください。

## 参考

- **bindgen**: rust-lang.github.io/rust-bindgen
- **Rustonomicon**: FFI
- **libc crate**: docs.rs/libc

*Keywords: C ABI, bindgen, c_int, c_long, c_void, callback, panic across FFI, #[repr(C)]*
