【发布时间】:2017-12-07 22:45:52
【问题描述】:
我和一位同事一直在摸索如何通过 FFI 将 bool 从 <stdbool.h>(又名 _Bool)返回给 Rust。
我们有想要从 Rust 使用的 C99 代码:
bool
myfunc(void) {
...
}
我们使用 extern C 块让 Rust 知道 myfunc:
extern "C" {
fn myfunc() -> T;
}
T 应该是什么具体类型?
Rust 在libc crate 中没有c_bool,如果你在互联网上搜索,你会发现人们讨论这个问题的各种 GitHub 问题和 RFC,但实际上并没有达成任何共识什么是正确和便携的:
- https://github.com/rust-lang/rfcs/issues/1982#issuecomment-297534238
- https://github.com/rust-lang/rust/issues/14608
- https://github.com/rust-lang/rfcs/issues/992
- https://github.com/rust-lang/rust/pull/46156
据我所知:
- C99 中
bool的大小未定义,除非它必须至少足够大以存储true(1) 和false(0)。换句话说,至少有一点长。 - 甚至可以是one bit wide。
- 它的大小可能是ABI defined。
This comment 建议如果 C99 bool 作为参数传入函数或作为返回值传出函数,并且 bool 小于 C @ 987654344@ 然后将其提升为与int 相同的大小。在这种情况下,我们可以告诉 Rust T 是 u32。
好吧,但是如果(出于某种原因)C99 bool 是 64 位宽怎么办? u32 还安全吗?也许在这种情况下,我们会截断 4 个最高有效字节,这很好,因为 4 个最低有效字节足以表示 true 和 false。
我的推理正确吗?在 Rust 获得 libc::c_bool 之前,您会为 T 使用什么?为什么它对于所有可能大小的 C99 bool(>=1 位)都是安全且可移植的?
【问题讨论】:
-
在这种情况下,我们可以告诉 Rust
T是u32— 不,你不能因为同样的问题发生:C doesn't define the size of anintother than as a minimum of 16 bits。 -
bool中必须至少有CHAR_BIT位,因此至少有 8 个(从CHAR_BIT >= 8开始)。链接中的脚注是说bool的width(定义为不包括填充位的术语)可能是1。 -
Shepmaster:哎呀,我的意思是说'c_int'而不是'u32'。这行得通吗?
-
@EddBarrett 肯定会更好,AFAICT,但 64 位的可能性仍然令人担忧。
-
牧长:Hrm。我认为我从中得到的是,问题仅在 C99 布尔值大于“T”时才存在。那么接下来,不应该使用最小的无符号 Rust 整数类型是安全的,即 u8 吗?如果 C bool 较大,我们截断。如果它更小,例如1 位,大概这必须扩展为内存单元或寄存器可以寻址的最小整数:一个字节,与 u8 一致。这个推理有什么漏洞吗?
标签: type-conversion rust boolean ffi