我有以下的C代码,它被编译为一个.so
文件:
void (*vlog_startup_routines[])() = {
hello_register,
0
};
在Rust中,我可以使用
#[no_mangle]
声明函数。我该如何公开一个名为vlog_startup_routines
的包含函数指针且以零结尾的数组符号?static
项目。在定义static
项目时,不幸的是,我们需要指定该数组的大小(截至Rust 1.13.0)。unsafe fn
)。然而,一个空指针是不安全的调用,所以Rust不允许创建一个空函数指针。但有一个技巧:当T
是一个指针(任何类型的指针,包括fat pointers和function pointers),Option<T>
与T
的大小相同1,而None
只是表示为空指针。因此,我们可以定义一个Option<fn()>
值的数组来获得所需的结果。
1对于其他类型,Option<T>
将比T
大,以存储判别式。#[no_mangle]
#[allow(non_upper_case_globals)]
pub static vlog_startup_routines: [Option<fn()>; 2] = [
Some(hello_register),
None
];
None
并将其包装在Some
中。macro_rules! one_for {
($_x:tt) => (1)
}
macro_rules! vlog_startup_routines {
($($func:expr,)*) => {
#[no_mangle]
#[allow(non_upper_case_globals)]
pub static vlog_startup_routines: [Option<fn()>; $(one_for!($func) +)* 1] = [
$(Some($func),)*
None
];
}
}
vlog_startup_routines! {
hello_register,
}
one_for
宏是因为我们需要在重复模式中引用一个参数符号(您可以有多个不同的重复,因此编译器需要知道您正在引用哪个),但我们不关心其值。None
啦!我无法弄清如何创建一个具有适当类型的NULL
。唉。 - Shepmaster
(void *)hello_register == (void *)vlog_startup_routines
,对吗? - Shepmasterextern
的 C 代码,以突出你想在 Rust 中实现该符号。此外,当你有一个库时,没有东西可以驱动程序,因此不会调用任何内容。使用 C 可执行文件会更好地表达问题。 - Shepmaster*hello_register == vlog_startup_routines
,因为数组包含函数的指针而不是函数本身。如果想要使用多个函数,这一点很重要。所以在 Rust 里,hello_register
就会像*const fn()
这样,允许进行算术运算。 - Matthieu M.