公开包含从Rust到C的零终止函数指针数组的C符号

我有以下C代码,编译为.so:

void (*vlog_startup_routines[])() = {
    hello_register,
    0
};

在Rust中,我可以使用#[no_mangle]声明函数.我如何公开一个名为vlog_startup_routines的符号,它是一个包含函数指针的数组,也是零终止的?

最佳答案 您需要定义一个类型为数组的静态项.不幸的是,在定义静态项时,我们需要指定该数组的大小(从Rust 1.13.0开始).

Rust中的函数指针不被认为是不安全的(除非你有一个不安全的fn).但是,空指针调用是不安全的,因此Rust不允许创建空函数指针.但是有一个技巧:当T是一个指针(无论哪种指针,包括胖指针和函数指针),Option<T> has the same size as T1, and None is simply represented as a null pointer.因此,我们可以定义一个Option< fn()>的数组.值以获得所需的结果.

1对于其他类型,选项< 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宏存在是因为我们需要引用一个重复模式中的一个参数符号(你可以有多个不同的重复,所以编译器需要知道你指的是哪一个)但我们不关心它值.

点赞