如何检查从C传递的函数指针是否为非NULL

时间:2015-07-17 17:05:05

标签: c rust ffi

以下示例代码

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)
}

因为fun类型为fn(i32) -> i32(它不是指针)。

所以我的问题是,如何保护call_c_function免受NULL指针取消引用?有没有办法检查从C传递的回调是否无效?

也许我必须更改call_c_function定义?

1 个答案:

答案 0 :(得分:10)

您可以使用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(...)(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) }
}