gpt4 book ai didi

rust - 从 Rust 填充 C 字符串指针的正确方法是什么?

转载 作者:行者123 更新时间:2023-11-29 07:53:28 25 4
gpt4 key购买 nike

我有一个我需要实现的 FFI 签名:

pub unsafe extern fn f(header_size: u32, header_ptr: *mut u8) -> i32;

FFI 调用者应提供缓冲区 header_ptr 和该缓冲区的大小 header_size。 Rust 预计会将一个字符串填充到该缓冲区中,最大为 header_size,如果成功则返回 0。 FFI 调用者应将字符串解释为 ASCII。

假设我有一个包含我想要提供的内容的 headers: &str,我该如何以最惯用的方式填充该缓冲区?

现在我有:

let header_bytes = slice::from_raw_parts_mut(header_ptr, header_size as usize);

if header_bytes.len() < headers.len() { return Errors::IndexOutOfBounds as i32; }

for (i, byte) in headers.as_bytes().iter().enumerate() {
header_bytes[i] = *byte;
}

但这感觉不对。

编辑,我认为这与this 不完全相同因为我的问题与字符串有关,而 IIRC 在将 &str 转换为 CString 时需要特别考虑。

最佳答案

由于 C 字符串只是以 0 结尾的字节数组,因此从 Rust 字符串转换非常简单。几乎每个有效的 Rust 字符串也是有效的 C 字符串,但您必须确保 C 字符串以 0 字符结尾,并且字符串中的其他任何地方都没有 0 字符。

Rust 提供了一种负责转换的类型:CString .

如果您的输入字符串已成功转换为 CString,您可以简单地复制字节而无需担心细节。

use std::slice;
use std::ffi::CString;

pub unsafe extern fn f(header_size: u32, header_ptr: *mut u8) -> i32 {
let headers = "abc";
let c_headers = match CString::new(headers) {
Ok(cs) => cs,
Err(_) => return -1, // failed to convert to C string
};
let bytes = c_headers.as_bytes_with_nul();

let header_bytes = slice::from_raw_parts_mut(header_ptr, header_size as usize);
header_bytes[..bytes.len()].copy_from_slice(bytes);

0 // success
}

fn main() {
let mut h = [1u8; 8];

unsafe {
f(h.len() as u32, h.as_mut_ptr());
}

println!("{:?}", h); // [97, 98, 99, 0, 1, 1, 1, 1]
}

请注意,为简洁起见,我省略了长度检查。如果缓冲区太短,header_bytes[..bytes.len()] 将会崩溃。如果从 C 调用 f,这是您要避免的事情。

关于rust - 从 Rust 填充 C 字符串指针的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51320714/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com