gpt4 book ai didi

rust - 在 C 库的回调函数中使用对类型参数的引用

转载 作者:行者123 更新时间:2023-11-29 08:23:25 25 4
gpt4 key购买 nike

我正在编写一个 C 库的 Rust 接口(interface),该库具有一个具有以下签名的函数:

typedef int (*callback_t)(const int *a, void *user_data);
void execute(callback_t callback);

我想要的是 Rust 接口(interface)的用户可以传递任何类型 T对于 user_data (user_data 未在 C 库中使用)。换句话说,在 Rust 方面,我想:

type Callback<T> = fn(a: &mut usize, user_data: &mut T) -> usize;

我尝试转换类型为 Callback<T> 的用户定义 Rust 函数到

extern "C" fn callback(a: *mut c_int, user_data: *mut c_void) -> c_int

as ,但这不起作用。我还尝试创建一个包装闭包。两次尝试均无效。

谁能帮帮我?

最佳答案

您不应该在不同的签名之间转换函数指针。这是灾难性的不安全并且会破坏你的程序(如果你幸运的话)。函数指针不可可互换,编译器无法神奇地使它们兼容。

你在这里有效地做的是接受一个用意大利语写的订单,划掉“language = Italian”,用“language = Russian”代替它,并期望俄罗斯厨师理解它,因为,嘿,它说它是用俄语!

首先,您对原始 C 类型的翻译可能是错误的。第一个参数是 *const c_int , 不是 *mut c_int . C 允许你投 const离开,但这很少是其他代码所期望的。

其次,您不应该将原始 C 指针转换为安全的 Rust 引用。如果 C 代码使用空指针调用,您的 Rust 代码将具有未定义的行为。除非 C 库保证两个指针永远不会为 null,并与程序员的第一个 child 签署血契约(Contract)并保证,否则不要相信它:首先检查指针。

第三,c_intusize不是同一类型。不要将它们混为一谈。用于 Rust 接口(interface)的正确类型是 c_int .

所以 Rust 中实际的 C 回调类型是:

type CCallback = Option<extern "C" fn(a: *const c_int, user_data: *mut c_void) -> c_int>;

Option是因为 C 函数指针可以为空,而在 Rust 中它们不能。

最后,Callback<T>未标有 extern "C" .使调用约定完全正确至关重要。

您打算转换为 C 回调类型的任何函数的签名都应该完全 C 回调签名。即:

extern "C" fn a_callback(a: *const c_int, user_data: *mut c_void) -> c_int {
::std::process::abort();
}

现在,您可能能够摆脱这个:

extern "C" fn a_callback<T>(a: *const c_int, user_data: *mut T) -> c_int {
::std::process::abort();
}

并强制Some(a_callback)CCallback .也就是说,我不能保证这对所有可能的情况都是正确的 T .

为了安全起见,您应该明确地将所有 Rust 回调函数包装在一个翻译函数中。这最容易通过宏完成,给定 Rust 函数的名称,生成一个 C 垫片。

macro_rules! shim {
($c:ident => $r:ident) => {
extern "C" fn $c(a: *const c_int, user_data: *mut c_void) -> c_int {
if a.is_null() {
::std::process::abort()
}
if user_data.is_null() {
::std::process::abort()
}
// NOTE: You need to make *absolutely certain* that this cast
// of user_data is valid.
let res: i32 = $r(&*a, &mut *(user_data as *mut _));
res as c_int
}
};
}

shim!(another_callback_c => another_callback);

fn another_callback(a: &c_int, user_data: &mut u8) -> i32 {
// Do something...
::std::process::abort()
}

关于rust - 在 C 库的回调函数中使用对类型参数的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52831604/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com