在Rust中创建C函数指针的接口
我可能没有正确描述我的问题标题,如果需要请编辑它。
我正在尝试为LXC库创建一个Rust接口,这是用C语言编写的。
我已经成功调用了像lxc_get_version
或lxc_container_new
这样的简单函数,但我无法访问struct lxc_container
块中描述的struct lxc_container
。
这是我的代码的一部分:
#[link(name = "lxc")] extern { // LXC part fn lxc_get_version() -> *const c_char; fn lxc_container_new(name: *const c_char, configpath: *const c_char) -> LxcContainer; // LXC container parts fn is_defined(container: &LxcContainer) -> bool; }
这是一个错误:
note: test.o: In function `LxcContainer::is_defined::heb2f16a250ac7940Vba': test.0.rs:(.text._ZN12LxcContainer10is_defined20heb2f16a250ac7940VbaE+0x3e): undefined reference to `is_defined'
编辑:我已经管理了C结构中的函数称为函数指针。 我试过谷歌像“Rust C函数指针”,但没有运气。
当你看到这样的东西时(在C中):
struct S { void (*f)(int, long) }
这意味着struct S
包含一个名为f
的字段,它是一个指向函数的指针。 这并不意味着库本身暴露了一个名为f
的函数。 例如,这是有效的:
void some_function_1(int x, long y) { ... } void some_function_2(int a, long b) { ... } int main() { struct S s1; s1.f = some_function_1; struct S s2; s2.f = some_function_2; }
这里struct struct s1
包含指向some_function_1
的指针, s2
包含指向some_function_2
的指针。
当您在Rust中为某些C库编写FFI绑定时,通常会为C结构定义Rust对应项。 像rust-bindgen
这样的工具甚至可以自动执行此操作。 在你的情况下,你将不得不写这样的东西:
#[repr(C)] struct LxcContainer { name: *mut c_char, configfile: *mut c_char, // ... numthreads: c_int, // ... is_defined_f: extern fn(c: *mut LxcContainer) -> bool, state_f: extern fn(c: *mut LxcContainer) -> *const c_char, // ... }
也就是说,奇怪的C函数指针类型对应于Rust中的extern fn
函数指针类型。 您也可以编写extern "C" fn(...) -> ...
,但"C"
限定符是默认值,因此不需要。
你必须写这样的东西来调用这些函数:
impl LxcContainer { fn is_defined_f(&mut self) -> bool { unsafe { (self.is_defined_f)(self as *mut LxcContainer) } } }
您需要转换对原始指针的引用,并且还需要在括号中包装self.is_defined_f
,以便消除方法调用和字段访问之间的歧义。
你可以在这里找到关于Rust的FFI的更多信息 。 但是,函数指针在那里进行了非常简单的解释。