gpt4 book ai didi

rust - 为什么 C 结构在从 Rust 读取时返回未对齐的垃圾数据?

转载 作者:行者123 更新时间:2023-11-29 08:18:46 25 4
gpt4 key购买 nike

我正在尝试用 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;
}

该结构表示一个链表,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();
}

这会读取垃圾数据——指针没有正确对齐,字符串是错误的且非 null 终止,下一个指针指向随机数据(直接从 C 调用函数时列表的大小不同) .

我尝试使用函数返回指向 elem 的指针并且只使用指针,我尝试从 el 的地址转换 str - 它总是读取相同的垃圾数据。如何使其正确对齐?

我知道如何使用指针而不是数组来完成它,这就是它在 Rust 文档中演示的方式,但我无法更改 C 代码。

最佳答案

在我专门为这种情况编写了一个示例库之后,我发现这不是一个外部问题,而是一个 CStr 问题。由于它在示例中已修复,我将缓冲区切片到第一个 NUL 终止符的位置,因此我提供了我为正确外部化而编写的示例。

list.c

#include <stdlib.h>
#include <string.h>

struct elem {
char data[5];
struct elem* next;
};

struct elem* get_list() {
struct elem* head = malloc(sizeof(struct elem));
strcpy(head->data, "1");

struct elem* el = malloc(sizeof(struct elem));
head->next = el;

strcpy(el->data, "2");

el->next = malloc(sizeof(struct elem));
el = el->next;
strcpy(el->data, "3");
el->next = NULL;

return head;
}

ma​​in.rs

use std::ffi::CStr;

#[repr(C)]
pub struct elem {
pub data: [u8; 5],
pub next: *const elem
}

#[link(name = "list", kind = "static")]
extern {
pub fn get_list() -> *const elem;
}

fn main() {
unsafe {
let mut list = get_list();
// Note, that, if we call from_bytes_with_nul it will throw
// an NulInternal error, therefore,
// we have to slice the buffer to the first NUL-terminator
while !list.is_null() {
let mut null_pos = (*list).data.len() - 1;
{
for i in 0..(*list).data.len() {
if (*list).data[i] == 0 {
null_pos = i + 1;
break
}
}
}
let str = CStr::from_bytes_with_nul(
(*list).data[..null_pos]
).unwrap();
println!("{:?}", str);
list = (*list).next;
}
}
}

输出

"1"
"2"
"3"

实现的关键方面:

  • 定义相同的结构,用#[repr(C)]注释,所以它会是以与 C 相同的方式对齐。

  • 定义 extern 函数以返回指向结构的 const 指针。

  • 使用指针代替 std::mem::transmute

  • 小心空指针和终止符

关于rust - 为什么 C 结构在从 Rust 读取时返回未对齐的垃圾数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45061755/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com