【问题标题】:How to create a struct in Rust where the last element is an array of variable length?如何在 Rust 中创建最后一个元素是可变长度数组的结构?
【发布时间】:2023-02-23 20:24:32
【问题描述】:

我正在尝试在 Rust 中创建一个动态的 LOGPALETTE 结构。这个结构的最后一个字段是名义上声明为 1 个元素的数组,但实际上它可以是任意数量的元素的数组。我们在堆中分配结构时指定元素的数量。

这就是我在 C 中的做法:

PALETTEENTRY entry = {0};

LOGPALETTE* pLogPal = (LOGPALETTE*)malloc(
    sizeof(LOGPALETTE) + 2 * sizeof(PALETTEENTRY) // room for 2 elements
);
pLogPal->palNumEntries = 2;      // inform we have 2 elements
pLogPal->palPalEntry[0] = entry; // fill the 2 elements
pLogPal->palPalEntry[1] = entry;

// use pLogPal...

free(pLogPal);

考虑到 LOGPALETTEPALETTEENTRY 声明,我如何在 Rust 中编写这个?

【问题讨论】:

  • Nitpick:使用官方的windowswindows-sys crates。
  • 可能首先需要将地址the bug in the C code,然后mem::transmute 转化为 Rust 代码。

标签: arrays winapi rust malloc


【解决方案1】:

不幸的是,Rust 不直接支持 VLA。因此,您需要手动执行此操作(不比 C 差,但在 C 中您可以使用大多数语言的工具来处理指针,而在 Rust 中您必须使用原始指针并且不能使用引用)。您还需要非常小心不要创建引用,因为references can only be used to read the data within the size of the type they are pointing to。您也不能创建对未初始化内存的引用。

这是一个这样做的例子:

unsafe {
    // Allocate space for 2 elements (one is already there).
    let layout = std::alloc::Layout::new::<tagLOGPALETTE>()
        .extend(std::alloc::Layout::array::<tagPALETTEENTRY>(1).unwrap())
        .unwrap()
        .0;
    let log_pal = std::alloc::alloc(layout).cast::<tagLOGPALETTE>();
    if log_pal.is_null() {
        std::alloc::handle_alloc_error(layout);
    }
    // Don't use `*` or `=`, it will create a reference!
    std::ptr::addr_of_mut!((*log_pal).palNumEntries).write(2);
    let entry = std::mem::zeroed::<tagPALETTEENTRY>();
    std::ptr::addr_of_mut!((*log_pal).palPalEntry[0])
        .add(0)
        .write(entry);
    std::ptr::addr_of_mut!((*log_pal).palPalEntry[0])
        .add(1)
        .write(entry);

    // Here, after you initialized them, you can create a slice of the entries:
    let entries = std::slice::from_raw_parts(std::ptr::addr_of!((*log_pal).palPalEntry[0]), 2);
    // But you can't create a reference to the whole type, even without accessing the entires
    // (only other fields), because you didn't initialize `palVersion`!
}

【讨论】:

    猜你喜欢
    • 2020-01-31
    • 1970-01-01
    • 2023-03-04
    • 2015-11-25
    • 2021-04-26
    • 1970-01-01
    • 2017-07-25
    相关资源
    最近更新 更多