Rust 在C库的回调函数中使用对类型参数的引用
我正在为一个具有以下签名的函数的C库编写一个Rust接口:Rust 在C库的回调函数中使用对类型参数的引用,rust,ffi,Rust,Ffi,我正在为一个具有以下签名的函数的C库编写一个Rust接口: typedef int(*callback_t)(常量int*a,void*user_数据); 无效执行(回调\u t回调); 我希望Rust界面的用户可以为user\u data传递任何类型的T(user\u data不在C库中使用)。换句话说,在生锈方面,我希望: type Callback=fn(a:&mut usize,user_data:&mut T)->usize; 我尝试将类型为Callback的用户定义的Rust函数
typedef int(*callback_t)(常量int*a,void*user_数据);
无效执行(回调\u t回调);
我希望Rust界面的用户可以为user\u data
传递任何类型的T
(user\u data
不在C库中使用)。换句话说,在生锈方面,我希望:
type Callback=fn(a:&mut usize,user_data:&mut T)->usize;
我尝试将类型为Callback
的用户定义的Rust函数强制转换为
extern“C”fn回调(a:*mut C_int,user_data:*mut C_void)->C_int
将设置为
,但这不起作用。我还尝试创建一个包装封口。两次尝试都没有成功
有人能帮我吗?您不应该在不同的签名之间强制转换函数指针。这是灾难性的不安全,并将炸毁你的程序(如果你幸运的话)。函数指针是不可交换的,编译器不能神奇地使它们兼容 实际上,你在这里做的是接受一份用意大利语写的订单,划掉“language=意大利语”,用“language=Russian”替换,并希望俄罗斯厨师能理解,因为,嘿,上面说的是俄语 首先,您对原始C类型的翻译可能是错误的。第一个参数是
*const c_int
,而不是*mut c_int
。C确实允许您丢弃const
,但这很少是其他代码所期望的
其次,您不应该将原始C指针转换为安全的引用。如果C代码使用空指针调用,则Rust代码将具有未定义的行为。除非C库保证这两个指针在与程序员的第一个孩子签订的血缘契约中永远不会为空,否则不要相信它:首先检查指针
第三,c_int
和usize
不是同一类型。不要把它们混为一谈。防锈界面使用的正确类型为c_int
所以Rust中实际的C回调类型是:
type CCallback = Option<extern "C" fn(a: *const c_int, user_data: *mut c_void) -> c_int>;
现在,您可能可以通过以下方式逃脱:
extern "C" fn a_callback<T>(a: *const c_int, user_data: *mut T) -> c_int {
::std::process::abort();
}
您不应该在不同的签名之间强制转换函数指针。这是灾难性的不安全,并将炸毁你的程序(如果你幸运的话)。函数指针是不可交换的,编译器不能神奇地使它们兼容 实际上,你在这里做的是接受一份用意大利语写的订单,划掉“language=意大利语”,用“language=Russian”替换,并希望俄罗斯厨师能理解,因为,嘿,上面说的是俄语 首先,您对原始C类型的翻译可能是错误的。第一个参数是
*const c_int
,而不是*mut c_int
。C确实允许您丢弃const
,但这很少是其他代码所期望的
其次,您不应该将原始C指针转换为安全的引用。如果C代码使用空指针调用,则Rust代码将具有未定义的行为。除非C库保证这两个指针在与程序员的第一个孩子签订的血缘契约中永远不会为空,否则不要相信它:首先检查指针
第三,c_int
和usize
不是同一类型。不要把它们混为一谈。防锈界面使用的正确类型为c_int
所以Rust中实际的C回调类型是:
type CCallback = Option<extern "C" fn(a: *const c_int, user_data: *mut c_void) -> c_int>;
现在,您可能可以通过以下方式逃脱:
extern "C" fn a_callback<T>(a: *const c_int, user_data: *mut T) -> c_int {
::std::process::abort();
}
“C确实允许您丢弃常量”,是和否,允许您确定,但尝试修改对象是未定义的行为。“现在,您可能可以这样做:“,如果我们只讨论C,则没有
void*
和T*
是不兼容的指针。@Stargateur:但它们的大小应该相同(对于size
类型),在这些情况下,void*
只是被用作一个不透明的负载。没有人不允许系统中的指针大小不一样,如果我记得的话,C要求所有指向结构的指针也兼容enum,但是void*
允许有任何表示,所以C要求隐式或显式转换为void*,这也是为什么必须使用printf(“%p”((void*)p)强制转换指针的原因代码>。但若一个系统运行生锈,我不认为指针会有时髦的表示,这就是为什么我说“若我们只讨论C”。谢谢!在本例中,当我试图简化实际的API时,const
是一个错误。在我的示例中,我之所以使用usize
,是因为我想对用户隐藏c_int
。“c确实允许您丢弃常量”,是和否,允许您确定,但尝试修改对象是未定义的行为。现在,您可能可以这样做:“,如果我们只讨论c,没有void*
和T*
是不兼容的指针。@Stargateur:但是它们应该是相同大小的(对于大小的
类型),在这种情况下,void*
只是被用作不透明的负载。没有人禁止指针大小不同的系统,如果我记得的话,C要求所有指向结构的指针都兼容enum,但void*
允许有任何表示,因此C要求隐式或显式转换为void*,这也是必须使用printf(“%p”,(void*)p)转换指针的原因代码>。但若一个系统运行生锈,我不认为指针会有时髦的表示,这就是为什么我说“若我们只讨论C”。谢谢!在本例中,当我试图简化实际的API时,const
是一个错误。在我的示例中使用usize
的原因是我想从