我想在Rust中包装一个C函数 . C函数 struct elem* get_list()
返回以下结构:
struct elem {
char data[5],
struct elem* next
};
在Rust中,我已按以下方式声明了该函数 . C函数的声明返回 *const c_void
,如旧版本的Rust文档中所述,在撰写本文时我无法找到 . 我尝试返回 *const elem
并使用指针,实现相同的结果:
extern "C" {
pub fn get_list() -> *const c_void;
}
struct表示链表, next
是指向列表下一个元素的指针 . 在Rust内部,我以下列方式声明了结构:
#[repr(C)]
pub struct elem {
pub data: [u8; 5],
pub next: *const c_void,
}
该函数返回 *const c_void
指向链表的第一个元素(类型为 elem
) . 我正在尝试使用以下代码读取链表的元素:
let head = get_list();
while !head.is_null() {
let el: &elem = mem::transmute(head);
let str = el.data;
let str = CStr::from_bytes_with_nul(&str).unwrap();
//do something
head = el.next();
}
这会读取垃圾数据 - 指针未正确对齐,字符串都是错误且非空终止,下一个指针会导致随机数据(当从C直接调用函数时,列表具有不同的大小) .
我尝试使用函数返回一个指向 elem
的指针并且仅使用指针,我尝试从 el
的地址转换 str
- 它总是读取相同的垃圾数据 . 如何使其正确对齐?
我知道如何使用指针而不是数组来实现它,这就是在Rust文档中演示它的方式,但我无法更改C代码 .
1 回答
在我为这个案例编写了一个示例库之后,我发现它不是一个外部问题,而是一个
CStr
. 正如在示例中修复的那样,我将缓冲区切片到第一个NUL终结符的位置,我提供了我为正确的externing编写的示例 .list.c
main.rs
产量
实施的关键方面:
定义相同的结构,用
#[repr(C)]
注释,因此它将以与C 1相同的方式对齐 .定义extern函数以返回指向结构的const指针 .
使用指针而不是
std::mem::transmute
小心使用空指针和终结符