I'm trying to write a Rust wrapper over the C++ library, where the pointer to array of C-style string is defined as:
char ***name;
In C++ I can iterate over strings easily:
for(int i=0;i<n;++i)
std::cout << std::string(*(name[i])) << std::endl;
which gives correct results.
However, in rust I can't figure out how to do this correctly.
The bindings to C++ library are generated by bindgen correctly and name is presented as
pub name: *mut *mut *mut ::std::os::raw::c_char
So, I'm trying the following:
// Get a slice of pointers to strings of size n, n is known and is correct
// The type of names is &[*mut i8]
let names = unsafe{ std::slice::from_raw_parts(*(name), n) };
// Iterates over a slice. ptr: &*mut i8
for ptr in names.iter() {
// Constructs a c-string from *mut i8
let cs = unsafe{ CStr::from_ptr(*ptr) };
// Shoud print a string, but gives rubbish instead
println!("{:?}",cs);
}
But this prints rubbish and all lines of output are the same and of size 2, while the strings are different and of different length:
"\x90\""
"\x90\""
"\x90\""
"\x90\""
"\x90\""
"\x90\""
I'm definitely missing something obvious, but can't find any errors. Any help is appreciated!
Your rust code does not match the layout you describe with your C++ example. Here is a simulation of the situation, with the memory layout matching your description.
Using
*(name[i])to obtain a string on the C side tells us thatnameis actually an array and each element is a pointer to achar *.I tried to mimic this layout on the Rust side. Many structs exist and each of them has a
char *member. In a vector, we collect the addresses of all thechar *members. Then, this vector is only known as the address of its first element and its number of elements.Maybe the actual layout on the C side is not exactly what you described?