如何将char转换为libc :: c_char?

时间:2017-01-19 19:25:34

标签: char rust ffi

我有一个C函数:

Node * first_element_by_path(const Node * node, const char * path, char delimiter);

还有一个Rust粘贴功能:

pub fn first_element_by_path(node: *mut CNode, path: *const c_char, delimiter: c_char) -> *mut CNode;

它希望c_char作为分隔符。我想向其发送char,但c_chari8而不是char。在这种情况下,如何将Rust char转换为i8c_char

1 个答案:

答案 0 :(得分:9)

你在问这个问题:

  

如何将32位数字拟合为8位值?

立即得到答案:"扔掉大部分比特":

let c = rust_character as libc::c_char;

然而,这应该让你停下来问问题:

  • 正确编码的其余位是什么?
  • 我扔掉的那些东西怎么样?

Rust char允许编码所有Unicode标量值。这段代码的您的期望行为是什么:

let c = '' as libc::c_char;

可能不会创建值-87,非ASCII值!或者这个不那么愚蠢,也许更现实的变体,即-17

let c = 'ï' as libc::c_char;

然后你必须问:C代码对一个角色意味着什么? C代码认为字符串是什么编码? C代码如何处理非ASCII文本?

最安全的事情可能是断言该值在ASCII范围内:

let c = 'ï';
let v = c as u32;
assert!(v <= 127, "Invalid C character value");
let v = v as libc::c_char;

您也可以返回Result类型,而不是断言,表示该值超出范围。

  

我应该更改我的函数(将调用粘合函数的函数)来接收c_char而不是char吗?

这取决于。这可能只是将问题进一步推向堆栈;现在每个调用者必须决定如何创建c_char并担心128到255之间的值。如果代码的语义是这样的,那么值必须是ASCII字符,然后编码你的类型。具体来说,您可以使用ascii crate之类的内容。

在任何一种情况下,您都会将失败的可能性转移到其他人的代码中,这会让您的生活变得更轻松,而且可能会使调用者更加沮丧。