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

公开包含从Rust到C的函数指针的零终止数组的C符号,rust,ffi,Rust,Ffi,我有下面的C代码,它被编译为。因此: void (*vlog_startup_routines[])() = { hello_register, 0 }; 在Rust中,我可以使用#[no\u mangle]声明函数。如何公开名为vlog\u startup\u routines的符号,该符号是一个包含函数指针的数组,也是以零结尾的?您需要定义一个类型为数组的静态项。不幸的是,在定义静态项时,我们需要指定该数组的大小(从1.13.0开始) Rust中的函数指针不被认为是不安全的

我有下面的C代码,它被编译为
。因此

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

在Rust中,我可以使用
#[no\u mangle]
声明函数。如何公开名为
vlog\u startup\u routines
的符号,该符号是一个包含函数指针的数组,也是以零结尾的?

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

Rust中的函数指针不被认为是不安全的调用(除非您有一个
不安全的fn
)。然而,调用空指针并不安全,因此Rust不允许创建空函数指针。但是有一个技巧:当
T
是指针时(无论哪种类型的指针,包括胖指针和函数指针)。因此,我们可以定义一个
选项
值数组来获得所需的结果

1对于其他类型,
选项
将大于
T
以存储判别式

#[no_mangle]
#[allow(non_upper_case_globals)]
pub static vlog_startup_routines: [Option<fn()>; 2] = [
    Some(hello_register),
    None
];

注意:宏的
one\u存在是因为我们需要引用重复模式中的一个参数符号(您可以有多个不同的重复,因此编译器需要知道您引用的是哪一个),但我们不关心它的值。

有趣。数组只不过是一个指针,以0结尾是一个运行时属性。但是,我不知道如何跨FFI边界传递函数指针;你检查过现有的防锈文件了吗?@MatthieuM。这里基本上不存在数组指针<代码>(void*)hello_register==(void*)vlog_startup_例程
,对吗?我建议在提问时使用你的措辞。提供C代码使其看起来像是要调用该代码。最好提供使用
extern
的C代码来突出显示您希望在Rust中实现该符号。此外,当您有一个库时,没有任何东西可以驱动程序,因此不会调用任何东西。C可执行文件可以更好地表达这个问题。@Shepmaster:请注意
*hello\u register==vlog\u startup\u例程
,因为数组包含指向函数的指针,而不是函数本身,我想如果希望拥有多个函数,这很重要。所以在Rust中,
hello\u register
将类似于
*const fn()
我想,允许算术运算。@MatthieuM。也许你能帮我找出原因吗?
None
;当然我不知道如何使用适当的类型创建
NULL
。叹气。谢谢,我考虑过这个选项,但我认为可能有更好的选择,因为只有最后一个元素应该是0。我想还没有。
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,
}