示例代码如下
Rust部分:
#[no_mangle] pub extern fn call_c_function(value: i32,fun: fn(i32) -> i32) -> i32 { fun(value) }
而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; }
当然call_c_function的第二次调用会崩溃.
Rust编译器不会抱怨call_c_function中的不安全代码,因为从生锈的角度来看这段代码是安全的.也不允许简单地写:
if !fun.is_null() { fun(value) }
因为有趣的类型是fn(i32) – > i32(它不是指针).
所以我的问题是,如何保护call_c_function免受NULL指针取消引用?有没有办法检查从C传递的回调是否无效?
也许我必须改变call_c_function的定义?
解决方法
您可以使用Option< ...>表示可空函数指针.对于fn(…)类型的值具有NULL值是不正确的,因此对于这样的情况需要Option包装器.
例如,
#[no_mangle] pub extern fn call_c_function(value: i32,fun: Option<fn(i32) -> i32>) -> i32 { if let Some(f) = fun { f(value) } }
但是,有一点是额外的:fun是一个C函数,但类型fn(…)是一个Rust函数.它们不是直接兼容的(例如它们的调用约定不同),当与C函数指针交互时,需要使用extern“C”fn(…)(也就是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) } }