-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Description
URL to the section(s) of the book with this problem:
Description of the problem:
This listing is absolutely fine:
unsafe extern "C" {
safe fn abs(input: i32) -> i32;
}
fn main() {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
But it may set a better precedent to use std::ffi::c_int
for the parameter and return value of abs
. While c_int and i32 should be equivalent on all modern platforms, that doesn't extend to c_long.
See the documentation for c_int and c_long, in particular this note for c_long:
This type will always be i32 or i64. Most notably, many Linux-based systems assume an i64, but Windows assumes i32.
C: making simple things complicated since 1972! 😄
I did a little experiment and found that:
If I erroneously declare labs to take a i64, then the Rust compiler will happily allow this runtime truncation to happen with no warning on Windows. Unsurprising, as Rust has no way to know that it should be 32-bit on Windows unless we tell it.
safe fn labs(input: i64) -> i64;
However, if we use c_long instead, then the Rust compiler can catch the mismatch at compile time:
use std::ffi::c_long;
unsafe extern "C" {
safe fn labs(input: c_long) -> c_long;
}
Something like this:
| println!("Absolute value of {num2} according to C: {}", labs(num2));
| ---- ^^^^ expected `i32`, found `i64`
| |
| arguments to this function are incorrect
Though note that this compiler error only happens on Windows, and I saw no such errors or clippy warnings on macOS. Writing cross-platform code is difficult!
So while safe fn abs(input: i32) -> i32
should be perfectly fine, it may be good if readers are aware of c_int
and therefore adopt similar types at FFI boundaries.
Suggested fix:
use std::ffi::c_int;
unsafe extern "C" {
safe fn abs(input: c_int) -> c_int;
}
fn main() {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
With minor updates to the surrounding prose.
Since this example is using 32-bit ints and since the truncation is well-defined implementation-specific C behaviour (and not strictly unsafe), I'm not sure if it this potential logic bug with c_long
needs to be noted on the chapter on safety. What do you think?