如何在 Rust 中初始化 sigset_t 或用作 "out parameters" 的其他变量?
How can I initialize sigset_t or other variables used as "out parameters" in Rust?
我正在尝试了解更多关于 Rust 中的 FFI 以及与 C 库的链接,特别是 libc
。在我的“探索”过程中,我遇到了以下问题。
C 中的正常模式
void(* sig_set(int sig, void(*handler)(int))) {
// uninitialized sigaction structs
struct sigaction new_action, old_action;
// assign options to new action
new_action.sa_flags = SA_RESTART;
new_action.sa_handler = handler;
sigemptyset(&new_action.sa_mask);
if(sigaction(sig, &new_action, &old_action) < 0) {
fprintf(stderr, "Error: %s!\n", "signal error");
exit(1);
}
return old_action.sa_handler;
}
尝试使用 Rust
use libc; // 0.2.77
fn sig_init(sig: i32, handler: fn(i32) -> ()) -> usize {
unsafe {
let mut new_action: libc::sigaction;
let mut old_action: libc::sigaction;
new_action.sa_flags = 0x10000000;
new_action.sa_sigaction = handler as usize;
libc::sigemptyset(&mut new_action.sa_mask as *mut libc::sigset_t);
libc::sigaction(
sig,
&mut new_action as *mut libc::sigaction,
&mut old_action as *mut libc::sigaction,
);
old_action.sa_sigaction
}
}
编译器会抛出以下错误:
error[E0381]: assign to part of possibly-uninitialized variable: `new_action`
--> src/lib.rs:8:9
|
8 | new_action.sa_flags = 0x10000000;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `new_action`
error[E0381]: borrow of possibly-uninitialized variable: `old_action`
--> src/lib.rs:15:13
|
15 | &mut old_action as *mut libc::sigaction,
| ^^^^^^^^^^^^^^^ use of possibly-uninitialized `old_action`
这是有道理的,因为如果 sigemptyset
从 sa_mask
读取数据,可能会发生非常糟糕的事情。所以我在上面的第 3 行尝试了以下内容。
let mut new_action: libc::sigaction = libc::sigaction {
sa_sigaction: handler as usize,
sa_flags: 0x10000000,
sa_mask: mask,
};
这将不起作用,因为在上面的示例中缺少 _restorer
,但 _restorer
是私有的。我将如何解决这个问题或类似情况?你会使用类似 mem::transmute
的东西吗?
使用 mem::zeroed
怎么样?文档甚至说:
This is useful for FFI functions sometimes, but should generally be avoided.
标准库定义了几个类型和函数来处理初始化。它们是通用的,因此可用于初始化任何类型的值。
现代 Rust 建议在大多数情况下使用 MaybeUninit
。适用于您的情况,它看起来像:
use std::mem::MaybeUninit;
let mut new_action: libc::sigaction = MaybeUninit::zeroed().assume_init();
let mut old_action: libc::sigaction = MaybeUninit::zeroed().assume_init();
MaybeUninit
在 Rust 1.36 中得到了稳定。在此之前,您可以使用 std::mem::uninitialized()
,它会为您提供一个未初始化的值。 LLVM 将认为内容是未定义的,并将基于此执行积极的优化。您必须在读取任何值之前对其进行初始化。
更适合您的情况的是 std::mem::zeroed()
,它为您提供了一个存储空间中填满零的值。这个函数是unsafe
,因为这样的值不一定对所有类型都合法。 zeroed()
适用于“普通旧数据”(POD) 类型。适用于您的情况,它看起来像:
use std::mem;
let mut new_action: libc::sigaction = mem::zeroed();
let mut old_action: libc::sigaction = mem::zeroed();
我正在尝试了解更多关于 Rust 中的 FFI 以及与 C 库的链接,特别是 libc
。在我的“探索”过程中,我遇到了以下问题。
C 中的正常模式
void(* sig_set(int sig, void(*handler)(int))) {
// uninitialized sigaction structs
struct sigaction new_action, old_action;
// assign options to new action
new_action.sa_flags = SA_RESTART;
new_action.sa_handler = handler;
sigemptyset(&new_action.sa_mask);
if(sigaction(sig, &new_action, &old_action) < 0) {
fprintf(stderr, "Error: %s!\n", "signal error");
exit(1);
}
return old_action.sa_handler;
}
尝试使用 Rust
use libc; // 0.2.77
fn sig_init(sig: i32, handler: fn(i32) -> ()) -> usize {
unsafe {
let mut new_action: libc::sigaction;
let mut old_action: libc::sigaction;
new_action.sa_flags = 0x10000000;
new_action.sa_sigaction = handler as usize;
libc::sigemptyset(&mut new_action.sa_mask as *mut libc::sigset_t);
libc::sigaction(
sig,
&mut new_action as *mut libc::sigaction,
&mut old_action as *mut libc::sigaction,
);
old_action.sa_sigaction
}
}
编译器会抛出以下错误:
error[E0381]: assign to part of possibly-uninitialized variable: `new_action`
--> src/lib.rs:8:9
|
8 | new_action.sa_flags = 0x10000000;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `new_action`
error[E0381]: borrow of possibly-uninitialized variable: `old_action`
--> src/lib.rs:15:13
|
15 | &mut old_action as *mut libc::sigaction,
| ^^^^^^^^^^^^^^^ use of possibly-uninitialized `old_action`
这是有道理的,因为如果 sigemptyset
从 sa_mask
读取数据,可能会发生非常糟糕的事情。所以我在上面的第 3 行尝试了以下内容。
let mut new_action: libc::sigaction = libc::sigaction {
sa_sigaction: handler as usize,
sa_flags: 0x10000000,
sa_mask: mask,
};
这将不起作用,因为在上面的示例中缺少 _restorer
,但 _restorer
是私有的。我将如何解决这个问题或类似情况?你会使用类似 mem::transmute
的东西吗?
使用 mem::zeroed
怎么样?文档甚至说:
This is useful for FFI functions sometimes, but should generally be avoided.
标准库定义了几个类型和函数来处理初始化。它们是通用的,因此可用于初始化任何类型的值。
现代 Rust 建议在大多数情况下使用 MaybeUninit
。适用于您的情况,它看起来像:
use std::mem::MaybeUninit;
let mut new_action: libc::sigaction = MaybeUninit::zeroed().assume_init();
let mut old_action: libc::sigaction = MaybeUninit::zeroed().assume_init();
MaybeUninit
在 Rust 1.36 中得到了稳定。在此之前,您可以使用 std::mem::uninitialized()
,它会为您提供一个未初始化的值。 LLVM 将认为内容是未定义的,并将基于此执行积极的优化。您必须在读取任何值之前对其进行初始化。
更适合您的情况的是 std::mem::zeroed()
,它为您提供了一个存储空间中填满零的值。这个函数是unsafe
,因为这样的值不一定对所有类型都合法。 zeroed()
适用于“普通旧数据”(POD) 类型。适用于您的情况,它看起来像:
use std::mem;
let mut new_action: libc::sigaction = mem::zeroed();
let mut old_action: libc::sigaction = mem::zeroed();