如何处理将usize传递给期望uint32_t的C函数?

时间:2016-10-26 06:29:51

标签: c rust ffi

我正在围绕C库编写Rust包装器。 C库提供以下功能:

void lib_foo(const unsigned char *buf, uint32_t buf_len);

我创建了以下extern包装器:

fn lib_foo(buf: *const u8, buf_len: u32);

以及以下高级包装器:

pub fn foo(buf: &[u8]) {
    unsafe { lib_foo(buf.as_ptr(), buf.len() as u32) }
}

但是,从usizebuf.len()的类型)到u32的强制转换可能会导致大小被截断。解决这个问题的最佳方法是什么?

2 个答案:

答案 0 :(得分:4)

首先,请使用libc包装箱来填写类型。

即:extern fn lib_foo(buf: *const libc::c_uchar, buf_len: libc::uint32_t);

虽然时间略长,但会避免做出假设(unsigned char映射到u8)并自动进行翻译。

然后,进入高级包装器。

没有任何假设,最简单的解决方案就是恐慌并记录下来。

/// Calls `lib_foo`, ...
///
/// # Panics
///
/// If the size of the buffer is strictly greater than 2^32-1 bytes.
pub fn foo(buf: &[u8]) {
    assert!(buf.len() <= (std::u32::MAX as usize));

    unsafe { lib_foo(buf.as_ptr() as *const _, buf.len() as libc::uint32_t) }
}

然后,根据域名,可能会出现其他选项:

  • 饱和度可能是一种选择(使用std::cmp::min
  • 重复通话可能是另一个
  • ...

在任何情况下,如果行为的差异对于用户是可观察的,文档

答案 1 :(得分:0)

  • 如果使用lib_foo读取/写入块是有意义的,请将其包装在一个循环中,该循环处理2 ** 32的块(增加的偏移量),然后处理剩余部分。在大多数情况下,它会跳过循环,但在特殊情况下,它只会多次调用lib_foo
  • 如果截断是lib_foo的可接受行为,请以某种方式截断并告诉用户
  • 如果不是,请在len&gt; = 2 ** 32
  • 时大声抱怨