将包含从 Rust 到 C 的函数指针的零终止数组的 C 符号公开
Exposing a C symbol containing a zero terminated array of function pointers from Rust to C
我有以下编译为 .so
的 C 代码:
void (*vlog_startup_routines[])() = {
hello_register,
0
};
在 Rust 中,我可以用 #[no_mangle]
声明函数。我如何公开一个名为 vlog_startup_routines
的符号,它是一个包含函数指针的数组并且也是零终止的?
您需要定义一个 static
类型为数组的项。不幸的是,在定义 static
项时,我们需要指定该数组的大小(从 Rust 1.13.0 开始)。
Rust 中的函数指针不被认为是不安全的调用(除非你有一个 unsafe fn
)。但是,调用空指针是不安全的,因此 Rust 不允许创建空函数指针。但是有一个技巧:当T
是一个指针(无论是哪种指针,包括胖指针和函数指针)时,Option<T>
has the same size as T
1, and None
is simply represented as a null pointer。因此,我们可以定义一个 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
宏的存在是因为我们需要以重复模式引用其中一个参数符号(你可以有多个不同的重复,所以编译器需要知道是哪一个你指的是)但我们不关心它的价值。
我有以下编译为 .so
的 C 代码:
void (*vlog_startup_routines[])() = {
hello_register,
0
};
在 Rust 中,我可以用 #[no_mangle]
声明函数。我如何公开一个名为 vlog_startup_routines
的符号,它是一个包含函数指针的数组并且也是零终止的?
您需要定义一个 static
类型为数组的项。不幸的是,在定义 static
项时,我们需要指定该数组的大小(从 Rust 1.13.0 开始)。
Rust 中的函数指针不被认为是不安全的调用(除非你有一个 unsafe fn
)。但是,调用空指针是不安全的,因此 Rust 不允许创建空函数指针。但是有一个技巧:当T
是一个指针(无论是哪种指针,包括胖指针和函数指针)时,Option<T>
has the same size as T
1, and None
is simply represented as a null pointer。因此,我们可以定义一个 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
宏的存在是因为我们需要以重复模式引用其中一个参数符号(你可以有多个不同的重复,所以编译器需要知道是哪一个你指的是)但我们不关心它的价值。