我试图在Rust和C动态库之间编写一些绑定代码。在Rust书的帮助下,我能够链接动态库并调用外部函数。
我的问题是我必须向C库注册一些回调,但我无法做到:
#[link(name = "MyLibrary")]
extern "C" {
fn Auth_RegisterCallback(
auth: size_t,
name: *const c_char,
function: &fn(size_t) -> i32,
param: size_t,
);
}
fn Authenticate() {
unsafe {
Auth_RegisterCallback(
auth,
CString::new("OnAuthBegin").unwrap().as_ptr(),
OnAuthBegin,
param,
)
};
unsafe {
NowAuth_RegisterCallback(
auth,
CString::new("OnSuccess").unwrap().as_ptr(),
OnSuccess,
param,
)
};
}
fn OnAuthBegin(auth: size_t) -> i32 {
println!("Auth begin");
return 1;
}
此代码工作正常,因为extern块中的Auth_RegisterCallback
期望参数中的函数具有size_t
类型的一个参数。
我的问题是我有多个回调来注册不同的签名,如:
fn OnSuccess(context: size_t, success: size_t) -> i32 {
println!("Success");
return 1;
}
有没有办法传递参数中的函数,即使它们的签名不同?
答案 0 :(得分:1)
如果您的FFI采用任意指针,那就是您必须表示您的功能。使用libc::c_void
并转换函数指针:
extern crate libc;
use libc::{c_char, size_t, c_void};
use std::ffi::CString;
extern "C" {
fn Auth_RegisterCallback(
auth: size_t,
name: *const c_char,
function: *const c_void,
param: size_t,
);
}
fn authenticate() {
let auth = unimplemented!();
let param = unimplemented!();
unsafe {
Auth_RegisterCallback(
auth,
CString::new("OnAuthBegin").unwrap().into_raw(), // Memory leak
on_auth_begin as *const _,
param,
);
Auth_RegisterCallback(
auth,
CString::new("OnSuccess").unwrap().into_raw(), // Memory leak
on_success as *const _,
param,
)
};
}
fn on_auth_begin(auth: size_t) -> i32 {
println!("Auth begin");
return 1;
}
fn on_success(context: size_t, success: size_t) -> i32 {
println!("Success");
return 1;
}
您可能希望通过在FFI函数周围创建多个单独的包装来添加某些类型的安全性:
fn register_begin_callback(f: fn(ctx: size_t, arg1: u8)) {
let auth = unimplemented!();
let param = unimplemented!();
unsafe {
Auth_RegisterCallback(
auth,
CString::new("OnAuthBegin").unwrap().into_raw(), // Memory leak
f as *const _,
param,
);
}
}
另见: