示例代码如下
Rust部分:
#[no_mangle]
pub extern fn call_c_function(value: i32, fun: fn(i32) -> i32) -> i32 {
fun(value)
}
Run Code Online (Sandbox Code Playgroud)
而C部分:
int32_t call_c_function(int32_t value, int32_t (*fun)(int32_t));
int32_t triple(int32_t x)
{
return x*3;
}
int main(int argc, char *argv[])
{
int32_t value = 3;
int32_t result = call_c_function(value, triple);
printf("%d tripled is %d\n", value, result);
call_c_function(0, NULL); // Crash here
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
当然第二次召唤call_c_function会崩溃.Rust编译器不会抱怨里面的不安全代码call_c_function,因为从生锈的角度来看这段代码是安全的.也不允许简单地写:
if !fun.is_null() {
fun(value)
}
Run Code Online (Sandbox Code Playgroud)
因为fun类型是fn(i32) -> i32(它不是指针).
所以我的问题是,如何call_c_function防止NULL指针解除引用?有没有办法检查从C传递的回调是否无效?
也许我必须改变call_c_function定义?
huo*_*uon 11
您可以使用它Option<...>来表示可空函数指针.对于类型的值具有NULL值是不正确的,fn(...)因此对于这样的Option情况需要包装器.
例如,
#[no_mangle]
pub extern fn call_c_function(value: i32, fun: Option<fn(i32) -> i32>) -> i32 {
if let Some(f) = fun { f(value) }
}
Run Code Online (Sandbox Code Playgroud)
但是,还有一点:fun是C函数,但类型fn(...)是Rust函数.它们不是直接兼容的(例如它们的调用约定不同),在与C函数指针交互时需要使用extern "C" fn(...)(aka extern fn(...))类型:
#[no_mangle]
pub extern fn call_c_function(value: i32, fun: Option<extern fn(i32) -> i32>) -> i32 {
if let Some(f) = fun { f(value) }
}
Run Code Online (Sandbox Code Playgroud)