如何在 Rust 结构体中使用 C 数组。

3

我正在使用Rust编写驱动程序,需要将下面的C结构体转换为Rust等效结构体:

struct vfio_irq_set {
    __u32   argsz;
    __u32   flags;
    __u32   index;
    __u32   start;
    __u32   count;
    __u8    data[];
};

唯一给我带来麻烦的变量是数据数组。到目前为止,我有以下 Rust 结构:

#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set {
    argsz: u32,
    flags: u32,
    index: u32,
    start: u32,
    count: u32,
    data: *const u8,
}

用于初始化结构体并进行ioctl调用的rust代码如下:

let irq_set: vfio_irq_set = vfio_irq_set {
    argsz: (mem::size_of::<vfio_irq_set>() + mem::size_of::<RawFd>() * (MAX_INTERRUPT_VECTORS + 1) as usize) as u32,
    count: interrupt_vector,
    flags: VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
    index: VFIO_PCI_MSIX_IRQ_INDEX as u32,
    start: 0,
    data: &[event_fd as u8] as *const u8,
};

if unsafe { libc::ioctl(device_fd, VFIO_DEVICE_SET_IRQS, &irq_set) } == -1 {
    return Err(format!(
        "failed to VFIO_DEVICE_SET_IRQS. Errno: {}",
        unsafe { *libc::__errno_location() }
    ).into());
}

但是我总是会收到一个"failed to VFIO_DEVICE_SET_IRQS. Errno: 22"的错误提示。

有人知道我做错了什么吗?


它们不会有相同的布局。灵活的数据成员应该与结构的其余部分在连续的内存中,并且应该只占用存储数据所需的必要空间。您的示例并没有做到这一点。指针总是需要空间,占用固定数量的空间,并且指向它的任何数据都不与struct的其余部分连续。 - Alex Huszagh
2
此外,&[event_fd as u8] as *const u8 可能是不安全的:该数组是临时的,无法长时间存活。 - mcarton
你也将失去大小信息,因此即使数据不是临时的,它也无法安全地读取该数据。 - Alex Huszagh
1
是的,你们两个都是对的,这只是一种绝望的解决方法。我对 Rust 还很新,这是我以前从未见过的 :) - tzwickl
1个回答

1
在C语言中,最后一个字段为未指定大小的数组的结构体是动态类型结构体。数据位于结构体末尾,没有额外的间接层。
Rust的等价物不是指针(具有固定大小),而是切片。您的结构体在Rust中应该是:
#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set {
    argsz: u32,
    flags: u32,
    index: u32,
    start: u32,
    count: u32,
    data: [u8],
}

然而,这些类型目前并不真正可用,更实际的等效方法是:

#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set<T: ?Sized> {
    argsz: u32,
    flags: u32,
    index: u32,
    start: u32,
    count: u32,
    data: T,
}

您需要确保T是一个正确大小的数组或切片。

另请参见:


你认为这个问题怎么样?它还没有答案。你认为这个问题应该被关闭吗?你想要移动你的回答吗?那么关于链接问题的评论呢:它们是否已经更新? - Lukas Kalbertodt
1
@LukasKalbertodt,你似乎是对的。我回答了另一个问题,尽管我的回答还没有得到赞成,所以我现在不能将它作为重复的回答。 - mcarton
@mcarton 非常感谢您的回复,这个方法很有效 :) 我已经搜索了将近两个小时,但没有找到另一个方法,所以很抱歉在这里重复提问 :) - tzwickl
1
@tzwickl 不用担心重复提问!有几个不同表述但与原问题相关的其他问题总是很有用的。这样,人们可以更容易地找到原始答案。 - Lukas Kalbertodt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接