The best way depends on how it's used, if they are read only c syle strings then the first option should work. If they can get modified then I would treat them as a &mut [u8] as in the second option. If the thing consuming them may need to resize them then it gets complicated.
fn rust_cstring_notmut() {
let s = std::ffi::CString::new("foo").expect("Null byte in string");
let mut v: Vec<*mut std::ffi::c_void> = vec![];
// The data is null-terminated, it must not be modified since it comes from a non mutable CString.
// This would better be a Vec<*const std::ffi::c_void> to make that obvious.
v.push(s.as_ptr() as _);
}
fn rust_bytes() {
let mut s = "foo".as_bytes().to_vec();
let mut v: Vec<*mut std::ffi::c_void> = vec![];
// The data isn't null-terminated, and any changes to `s` can't change the length.
// If it should be null-terminated, make sure to add a null byte at the end before pushing the pointer.
v.push(s.as_mut_ptr() as _);
}```
first, you can use &raw to get a raw pointer; and second, casting a raw pointer don't need unsafe:
let name = c"test.txt";
let pname = name.as_ptr();
let mut pvec = vec![];
pvec.push(&raw const pname as *mut c_void);
I don't why you are doing this, just a reminder: be very careful if you are doing this in a loop, cause you might get a bunch of bad pointers if done incorrectly, e.g. the following code is INCORRECT:
let mut pvec: Vec<*mut c_void> = vec![];
for name in names {
let pname = name.as_ptr();
pvec.push(&raw const pname as _);
}
// use the vector as argument to ffi function
// !!! THIS IS WRONG !!!
unsafe { my_ffi_function(pvec.as_ptr(), pvec.len()) };