在 FFI 中使用 ()(和其他零大小类型)

ran*_*son 3 ffi rust

在 Rust 中执行 FFI 时()(或任何其他零大小类型)的等价物是什么?具体来说,我很好奇()在编写extern "C"函数时作为函数参数最合理的等价物是什么。

我的理解是零大小类型在 C 中无效,但 Rust 似乎允许在extern "C"函数中使用它们,例如:

#[no_mangle]
pub extern "C" fn test_ffi(input: ()) -> () {
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,返回()void在 C# 中声明函数相同。但是,我不清楚input在从 C 生成绑定时如何声明参数。我的印象是 ZST 不能在 C 中表示,因此不应该是 FFI 安全的。似乎nomicon 证实了这一点,说:

为了避免()在 FFI 中使用时出现警告,我们改为使用空数组 ( [u8; 0]),它与空类型一样有效,但与 FFI 兼容。

这似乎暗示这()不是 FFI 兼容的,但那[u8; 0]是(即使我希望它也是零尺寸)?

Sta*_*eur 5

()在 C 中没有等价物。有些人可能会争辩说void是等价物,但实际上并非如此。当然,它们有相似之处,在大多数情况下,它们可以像您说的那样互换:pub extern "C" fn test_ffi() -> ()将正确解释为void test_ffi(void). (注意:这里void在参数列表中意味着该函数没有参数,因此它不是空类型)。

你能想到的void什么,但是是()什么?不,它是一个空元组,而void实际上什么都不是。

我的印象是 ZST 不能用 C 表示,因此不应该是 FFI 安全的。

不,它们不能用 C 表示:pub extern "C" fn test_ffi(input: (), foo: i32) -> ()这里不清楚 Rust 编译器应该理解什么,因为void test_ffi(void, int32_t foo);在 C 中是无效的。

Nomicon使用空数组使类型不透明。我不建议这样做,但对于这个特定用例可能没问题。无论如何,C 中的不透明类型都是邪恶的。请注意,空数组在 C 中是非法的,因此它们只能在 Rust 端使用。

我建议永远不要在任何 FFI 中使用任何大小为零的类型。