本篇,咱们一起来研究 Rust 与 C 之间的回调函数传递。本篇的目标如下:
被调函数在 C 端,接收一个函数指针作为回调函数,并调用;
主函数在 Rust 中,在 Rust 中调用 C 端的这个函数;
在 Rust 中,传递一个 Rust 中定义的函数,到这个 C 端的被调函数中作为回调函数。
为什么要研究跨 FFI 的回调函数,因为
有可能想在底层事件(异步)框架中,注册一个函数,事件触发的时候,调用;
底层采用注册一个路由表的形式,在程序开始的时候,注册一堆函数操作进去;
其它。
这是一种常见需求,也是一种设计模式。
基础示例
话不多说,我们来设计一个示例流程:
C 端,设计一个函数,sum_square_cb01, 接收两个整型参数 a, b,和一个函数指针,计算 a2 + b2 的值,并且将值传递进第三个参数(函数中),进行打印;
Rust 端,定义一个回调函数 cb_func,在这个回调函数中,打印上述平方和;
Rust 端,引入 C 中定义的 sum_square_cb01;
在 Rust 的 main 中,调用 sum_square_cb01。
好,直接上代码。C 端:
// csrc/ccode01.c
#include<stdio.h>
typedef void (*SumSquareCB)(int result);
void sum_square_cb01(int a, int b, SumSquareCB cb) {
int result = a*a + b*b;
cb(result);
}
Rust 端:
// src/r01.rs
use std::os::raw::c_int;
pub type SumSquareCB = unsafe extern fn(c_int);
#[link(name = "ccode01")]
extern {
pub fn sum_square_cb01(a: c_int, b: c_int, cb: SumSquareCB);
}
pub unsafe extern fn cb_func(result: c_int) {
println!("The result in callback function is: {}", result);
}
fn main() {
unsafe {
sum_square_cb01(3, 4, cb_func);
}
}
两边代码其实挺简洁。不过也有要注意的一些地方。要点提醒:
两边都需要定义回调函数的类型(签名),而且定义要一致。
C 中定义:
typedef void (*SumSquareCB)(int result);
Rust 中定义:
pub type SumSquareCB = unsafe extern fn(c_int);
fn
是 Rust 中的函数指针类型。具体可参见标准库文档 fn,解释得非常详尽。
函数指针的功能就是指向函数代码片断,可以用函数指针来调用函数,效果跟函数名一样,如上面 C 代码中的
cb(result)
。
Rust 中的回调函数定义
pub unsafe extern fn cb_func(result: c_int) {
println!("The result in