我已经为C / C ++编写了一些FFI代码,
use libc::c_char;
use std::ffi::CString;
type arr_type = [c_char; 20]; // arr_type is the type in C
let mut arr : arr_type = [0; 20];
let s = "happy123";
let c_s = CString::new(s).unwrap();
let s_ptr = c_s.as_ptr();
如何使用字符串arr
更新s
?在C / C ++中,我可以使用memcpy
,strcpy
等...
我尝试了很多,比如使用rlibc :: memcpy,发现它不能和libc一起使用..但编译器不允许我通过,关于Rust的数组信息非常少
添加: 阅读完回复后,我想添加一些信息和更多问题。
1
在C ++中,我使用strcpy_s
将字符串复制到char数组,导致字符串的长度和数组的大小都是已知的。
我已尝试过以下两种方法。
std::iter::Zip
方法,看起来非常像strcpy_s
,但我不知道是否存在性能影响。
copy_nonoverlapping
方法,它使用as_mut_ptr()
将数组转换为指针然后没有长度信息,因为它在unsafe { }
块中,我尝试复制一个字符串更长然后数组并没有错误显示......我想知道这是否正常?
在Rust中是否有类似strcpy_s的函数?
2
我使用windows和msvc,对于char数组,我的意思是not deal with encoding
或使用default codepage encoding
。
在源文件中都可以:
C ++:
std::string s = "world is 世界";
std::wstring ws = L"world is 世界";
Qt的:
QString qs = QStringLiteral("world is 世界");
Python 3:
s = 'world is 世界'
但是在Rust,下面可能是错的?正如我在Eclipse Debug窗口中看到的那样。
let s = "world is 世界";
我发现了锈编码并尝试了这些:
use encoding::{Encoding, EncoderTrap};
use encoding::all::GB18030;
let s = "world is 世界";
let enc = GB18030.encode(&s , EncoderTrap::Strict);
在Rust有没有更好的方法?
答案 0 :(得分:2)
这是一个不需要不安全代码的解决方案,但不幸的是大多数方法都标记为不稳定。
#![feature(libc)]
#![feature(core)]
#![feature(collections)]
extern crate libc;
use libc::c_char;
use std::ffi::CString;
use std::slice::IntSliceExt;
type arr_type = [c_char; 20];
fn main() {
let mut c_string: arr_type = [0; 20];
let value = CString::new("happy123").unwrap();
c_string.clone_from_slice(value.as_bytes_with_nul().as_signed());
}
答案 1 :(得分:1)
我建议通过同时迭代数组和字符串来自动更新每个字符,并将字符串字符分配给数组字符。我将最后的\0
添加到Rust-string。
#![feature(libc)]
extern crate libc;
fn main() {
use libc::c_char;
type ArrType = [c_char; 20]; // arr_type is the type in C
let mut arr : ArrType = [0; 20];
let s = "happy123\0";
assert!(s.len() <= arr.len());
for (a, c) in arr.iter_mut().zip(s.bytes()) {
*a = c as i8;
}
}
在大多数情况下,llvm会将该循环优化为memcopy。
define internal void @_ZN4main20hf4c098c7157f3263faaE() unnamed_addr #0 {
entry-block:
%0 = alloca %"2.core::str::Bytes", align 8
%arg4 = alloca %str_slice, align 8
%1 = bitcast %"2.core::str::Bytes"* %0 to i8*
call void @llvm.lifetime.start(i64 16, i8* %1)
%2 = bitcast %str_slice* %arg4 to i8*
call void @llvm.lifetime.start(i64 16, i8* %2)
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* bitcast (%str_slice* @const26 to i8*), i64 16, i32 8, i1 false)
call void @_ZN3str3str5bytes20h68b1cf722a654e56XOgE(%"2.core::str::Bytes"* noalias nocapture sret dereferenceable(16) %0, %str_slice* noalias nocapture dereferenceable(16) %arg4)
call void @llvm.lifetime.end(i64 16, i8* %2)
call void @llvm.lifetime.end(i64 16, i8* %1) #3, !alias.scope !0, !noalias !3
call void @llvm.lifetime.end(i64 16, i8* %1)
ret void
}
答案 2 :(得分:1)
在C / C ++中,我可以使用memcpy,strcpy等...
在Rust中使用它们也没有问题:
extern { fn memcpy(dst: *mut libc::c_void, src: *const libc::c_void, len: libc::size_t); }
let t_slice: &mut [c_char] = &mut arr;
unsafe {
memcpy(t_slice.as_mut_ptr() as *mut libc::c_void,
s_ptr as *const libc::c_void,
c_s.as_bytes_with_nul().len() as libc::size_t);
}
但最好使用ptr module中的防锈等效std::ptr::copy_nonoverlapping:
let t_slice: &mut [c_char] = &mut arr;
unsafe {
ptr::copy_nonoverlapping(t_slice.as_mut_ptr(), s_ptr, c_s.as_bytes_with_nul().len());
}
但是,您应该注意unsafe
块,因此您有责任检查arr
中是否有足够的空间。