在 Rust 中将二维字节数组传递给 C

Pass 2D array of bytes to C in Rust

我用 C 写了一个函数,签名如下:

write_stuff(char **pages, uint32 page_count);

pages 将是一个包含 128 个元素的数组,每个元素要么为 NULL,要么指向一个 8192 字节的 char 数组。因此,一组具有固定已知大小的数组。

我需要在 Rust 中填充数组并将它们传递给 C 函数。当我使用 bindgen 生成 Rust 签名时,它会生成:

extern "C" {
    pub fn write_stuff(pages: *mut *mut ::std::os::raw::c_char, page_count: u32,);
}

现在,我如何在 Rust 中声明一个我可以填充并传递给这个函数的变量?

我试过这个:

let mut pages = [Option <[u8; 8192]>; 128];

但它无法编译。

这编译:

type MyPage = Option<[u8; 8192]>;
let myarray: [MyPage; 128] = [None; 128];

但我不清楚它是否会以正确的格式存储数据,或者如何适当地转换它:

let pages: *mut *mut ::std::os::raw::c_char = myarray.as_mut_ptr() as // what goes here?;

我相信您正在寻找的 Rust 类型是 &[Option<&[u8; 8192]>]。 C 版本使用双指针,所以你需要确保内部类型是一个引用。 Option<&T> 表明引用可以为空,并且 null pointer optimization 保证它与 T.

具有相同的大小

我已经测试过下面的代码可以正常工作, 但我不是 100% 确定这种类型转换是合理的 所以我会在生产代码中小心使用它。

生锈 main.rs

#[link(name = "mylib")]
extern "C" {
    pub fn write_stuff(pages: *mut *mut ::std::os::raw::c_char, page_count: u32);
}

pub fn write_stuff_rust(pages: &[Option<&[u8; 8192]>]) {
    unsafe { write_stuff(pages.as_ptr() as *mut _, pages.len() as u32) }
}

fn main() {
    let page1: [u8; 8192] = [b'a'; 8192];
    let page3: [u8; 8192] = [b'b'; 8192];
    let page4: [u8; 8192] = [b'c'; 8192];
    let page7: [u8; 8192] = [b'd'; 8192];

    let pages: Vec<Option<&[u8; 8192]>> = vec![
        Some(&page1),
        None,
        Some(&page3),
        Some(&page4),
        None,
        None,
        Some(&page7),
    ];

    write_stuff_rust(&pages);
}

C mylib.c

#include <stdio.h>
#include <stdint.h>

void write_stuff(char **pages, uint32_t page_count) {
    for (uint32_t i = 0; i < page_count; i++) {
        printf("%d=%p\n", i, pages[i]);
        if (pages[i]) {
            for (size_t j = 0; j < 8192; j++) {
                putchar(pages[i][j]);
            }
            putchar('\n');
        } else {
            puts("<empty>");
        }
    }
}