I have write some FFI code to C/C++,
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();
How can I update arr
with the String s
? In C/C++ I can use memcpy
, strcpy
etc...
I have tried many, like use rlibc::memcpy and found it can't be used with libc.. , but the compiler don't let me pass, there is very few info about array in Rust.
Add: After read the replys, I want to add some info and more question.
1.
In C++, I use strcpy_s
to copy string to char array, cause the length of string and the size of array are all known.
I have tried both methods below.
the std::iter::Zip
method, seems very like strcpy_s
, but I don't know if there is some performance affect.
the copy_nonoverlapping
method, it use as_mut_ptr()
cast the array to pointer then there is no length info, since it is in unsafe { }
block, and I have tried copy a string longer then the array and there is no error displays... I wonder if that's ok?
And is there a function in Rust like strcpy_s in C++?
2.
I'm using windows and msvc, for the char array, I mean not deal with encoding
or use default codepage encoding
.
below are all ok in source file:
C++:
std::string s = "world is 世界";
std::wstring ws = L"world is 世界";
Qt:
QString qs = QStringLiteral("world is 世界");
Python 3:
s = 'world is 世界'
But in Rust, below may be wrong? as I see in Eclipse Debug window.
let s = "world is 世界";
I found rust-encoding and tried these:
use encoding::{Encoding, EncoderTrap};
use encoding::all::GB18030;
let s = "world is 世界";
let enc = GB18030.encode(&s , EncoderTrap::Strict);
Is there any better way to do in Rust?
Here's one solution that doesn't require unsafe code, but unfortunately most of the methods are marked unstable.
#![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());
}
I suggest updating every character on its own by iterating over the array and the string simultaneously, and assigning the string characters to the array characters. I added the final \0
to the 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;
}
}
Try it out in the PlayPen
in most cases llvm will optimize that loop to a 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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With