Sie müssen ein static
Element definieren, dessen Typ ein Array ist. Bei der Definition eines Elements static
müssen wir leider die Größe dieses Arrays angeben (ab Rust 1.13.0).
Funktionszeiger in Rust gelten nicht als unsicher zum Anrufen (es sei denn, Sie haben eine unsafe fn
). Es ist jedoch nicht möglich, einen Nullzeiger aufzurufen, sodass Rust das Erstellen eines Nullfunktionszeigers nicht zulässt. Aber es gibt einen Trick: Wenn T
ist ein Zeiger (welcher Art von Zeiger, einschließlich Fat Pointer und Funktionszeiger), Option<T>
has the same size as T
1, and None
is simply represented as a null pointer. Daher können wir ein Array von Option<fn()>
Werten definieren, um das gewünschte Ergebnis zu erhalten.
Für andere Typen wäre Option<T>
größer als T
, um die Diskriminante zu speichern.
#[no_mangle]
#[allow(non_upper_case_globals)]
pub static vlog_startup_routines: [Option<fn()>; 2] = [
Some(hello_register),
None
];
Wenn Sie die Arraygröße angeben müssen, die Sie ärgert, dann können Sie ein Makro verwenden, das es für Sie berechnet. Als Bonus fügt dieses Makro die nachfolgende None
hinzu und umschließt jede Funktion in 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,
}
Hinweis: Die one_for
Makro existiert, weil wir eines der Parametersymbole in einem Wiederholungsmuster verweisen müssen (Sie mehrere unterschiedliche Wiederholungen haben kann, so dass der Compiler die Sie sich beziehen man wissen muss) aber wir interessieren uns nicht für seinen Wert.
Interessant. Ein Array ist nichts anderes als ein Zeiger, und wenn 0 beendet wird, ist es eine Laufzeiteigenschaft. Ich bin mir jedoch nicht sicher, wie man den Zeiger auf Funktionen über die FFI-Grenze hinausgibt; Haben Sie die bestehende Rust-Dokumentation überprüft? –
@MatthieuM. und der Array-Zeiger existiert hier grundsätzlich nicht; '(void *) hallo_register == (void *) vlog_startup_routines', oder? – Shepmaster
Ich würde vorschlagen, an Ihren Formulierungen zu arbeiten, wenn Sie Fragen stellen. Durch die Bereitstellung von C-Code sieht es so aus, als ob Sie diesen Code * aufrufen möchten. Es wäre besser gewesen, einen C-Code bereitzustellen, der ein "extern" verwendet, um hervorzuheben, dass Sie dieses Symbol in Rust implementieren möchten. Außerdem, wenn Sie eine Bibliothek haben, gibt es nichts, um das Programm zu steuern, also würde nichts angerufen werden. Eine C-ausführbare Datei würde das Problem besser ausdrücken. – Shepmaster