A colleague and I have been scratching our heads over how to return a bool
from <stdbool.h>
(a.k.a. _Bool
) back to Rust via the FFI.
We have our C99 code we want to use from Rust:
bool
myfunc(void) {
...
}
We let Rust know about myfunc
using an extern C
block:
extern "C" {
fn myfunc() -> T;
}
What concrete type should T
be?
Rust doesn't have a c_bool
in the libc
crate, and if you search the internet, you will find various GitHub issues and RFCs where people discuss this, but don't really come to any consensus as to what is both correct and portable:
As far as I can gather:
bool
in C99 is undefined other than the fact it must be at least large enough to store true
(1) and false
(0). In other words, at least one bit long.This comment suggests that if a C99 bool
is passed into a function as a parameter or out of a function as the return value, and the bool
is smaller than a C int
then it is promoted to the same size as an int
. Under this scenario, we can tell Rust T
is u32
.
All right, but what if (for some reason) a C99 bool
is 64 bits wide? Is u32
still safe? Perhaps under this scenario we truncate the 4 most significant bytes, which would be fine, since the 4 least significant bytes are more than enough to represent true
and false
.
Is my reasoning correct? Until Rust gets a libc::c_bool
, what would you use for T
and why is it safe and portable for all possible sizes of a C99 bool
(>=1 bit)?
As of 2018-02-01, the size of Rust's bool is officially the same as C's _Bool
.
This means that bool
is the correct type to use in FFI.
The rest of this answer applies to versions of Rust before the official decision was made
Until Rust gets a
libc::c_bool
, what would you use forT
and why is it safe and portable for all possible sizes of a C99 bool (>=1 bit)?
As you've already linked to, the official answer is still "to be determined". That means that the only possibility that is guaranteed to be correct is: nothing.
That's right, as sad as it may be. The only truly safe thing would be to convert your bool
to a known, fixed-size integral type, such as u8
, for the purpose of FFI. That means you need to marshal it on both sides.
Practically, I'd keep using bool
in my FFI code. As people have pointed out, it magically lines up on all the platforms that are in wide use at the moment. If the language decides to make bool
FFI compatible, you are good to go. If they decide something else, I'd be highly surprised if they didn't introduce a lint to allow us to catch the errors quickly.
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With