这段代码运行良好,但在 Rust nightly (1.2) 上会给出编译器警告
#[repr(C)]
struct DbaxCell {
cell: *const c_void
}
#[link(name="CDbax", kind="dylib")]
extern {
fn new_dCell(d: c_double) -> *const c_void;
fn deleteCell(c: *const c_void);
}
impl DbaxCell {
fn new(x: f64) -> DbaxCell {
unsafe {
DbaxCell { cell: new_dCell(x) }
}
}
}
impl Drop for DbaxCell {
fn drop(&mut self) {
unsafe {
deleteCell(self.cell);
}
}
}
它链接到 C 库并正确创建/删除单元对象。但是它会发出警告
src\lib.rs:27:1: 33:2 warning: implementing Drop adds hidden state to types, possibly conflicting with `#[repr(C)]`, #[warn(drop_with_repr_extern)] on by default
\src\lib.rs:27 impl Drop for DbaxCell {
\src\lib.rs:28 fn drop(&mut self) {
\src\lib.rs:29 unsafe {
\src\lib.rs:30 deleteCell(self.cell);
\src\lib.rs:31 }
\src\lib.rs:32 }
确保正确清理这些 DbaxCell
并且不发出警告的正确方法是什么?
最佳答案
我认为您将两个概念混为一谈。如果您希望结构的布局直接对应到结构的布局,则结构应该是 repr(C)
,因为 C 编译器会对其进行布局。也就是说,它具有相同的内存中 repr
esentation。
但是,如果您只是持有一个原始指针,并且不打算将持有结构传递回 C,那么您不需要。在这种情况下,简短的解决方案是“删除 repr(C)
".
解释一下这个错误...
implementing Drop adds hidden state to types, possibly conflicting with
#[repr(C)]
这已在 issue 24585 中讨论过.当一个对象被丢弃时,会设置一个隐藏标志(“状态”),指示该对象已被丢弃,从而防止发生多次丢弃。但是,隐藏位意味着您在 Rust 中看到的内容与在 C 中的结构字节不对应,这否定了 repr(C)
的目的。
作为 cribbed from @bluss :
Low level programmers, don't worry: future Rust will remove this drop flag entirely.
和
Use
repr(C)
to pass structs in FFI, and useDrop
on "regular Rust" structs if you need to. If you need both, embed therepr(C)
struct inside the regular struct.
假设我们有一个库,它公开了一个带有两个 8 位数字的 C 结构,以及获取和返回该结构的方法:
typedef struct {
char a;
char b;
} tuple_t;
tuple_t tuple_increment(tuple_t position);
在这种情况下,您肯定想模仿该结构并匹配 Rust 中的 C 表示:
#[repr(C)]
struct Tuple {
a: libc::char,
b: libc::char,
}
但是,如果库返回了指向结构的指针,并且您永远不需要插入它(结构是不透明),那么您无需担心 repr(C )
:
void tuple_increment(tuple_t *position);
然后你可以使用那个指针并实现 Drop:
struct TuplePointer(*mut libc::c_void);
impl Drop for TuplePointer {
// Call the appropriate free function from the library
}
关于使用 Drop trait 释放 repr(C) 结构的正确习惯用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30742004/