我和同事一直在考虑如何通过 FFI 从 C99 代码中返回 <stdbool.h>
(即 _Bool
) 到 Rust 中的 bool
。
我们想要在 Rust 中使用以下 C99 代码:
bool
myfunc(void) {
...
}
我们使用 extern C
块将 Rust 了解 myfunc
:
extern "C" {
fn myfunc() -> T;
}
具体来说,T
应该是什么类型?
Rust 的 libc
库中没有 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)之外。换句话说,至少为一个比特长。 - 它甚至可能是一位宽。 - 它的大小可能是ABI定义的。 这条评论表明,如果将C99 bool作为参数传递到函数中或作为返回值传递出函数,并且bool小于C int,则会将其提升为与int相同的大小。在这种情况下,我们可以告诉Rust T是u32。
好吧,但是如果(由于某种原因)C99 bool宽度为64位呢? u32仍然安全吗?也许在这种情况下,我们截断最高的4个字节,这是可以接受的,因为最低的4个字节已经足以表示true和false。
我的推理正确吗?在Rust获得libc::c_bool
之前,您将使用什么来代替T
,为什么它对C99 bool
(>= 1位)的所有可能大小都是安全和可移植的?
T
是u32
— 因为同样的问题也会出现:C 并没有定义int
的大小,除了最小为 16 位。 - Shepmasterbool
类型至少要有CHAR_BIT
位,因此至少为 8 位(因为CHAR_BIT >= 8
)。链接中的脚注指出bool
的 宽度,这个术语定义时不包括填充位,可能是 1。 - user2357112