Florian Doyon
Florian Doyon

Reputation: 4186

Convert from a fixed-sized c_char array to CString

My FFI binding returns a struct with fixed-size c_char arrays, and I would like to turn those into std::ffi::CString or std::String.

It looks like the CString::new function coerces the pointer to a vector.

use std::ffi::CString;
use std::os::raw::c_char;

#[repr(C)]
pub struct FFIStruct {
    pub Id: [::std::os::raw::c_char; 256usize],
    pub Description: [::std::os::raw::c_char; 256usize],
}

fn get_struct() -> Option<FFIStruct> {
    println!("cheating");
    None
}

pub fn main() {
    match get_struct() {
        Some(thing) => 
            println!("Got id:{}",CString::new(thing.Id.as_ptr())),

        None => (),
    }
}

Here is the Rust Playground link.

Upvotes: 6

Views: 5442

Answers (3)

Ivar Svendsen
Ivar Svendsen

Reputation: 91

There is also this kind of solution:

fn zascii(slice: &[c_char]) -> String {
  String::from_iter(slice.iter().take_while(|c| **c != 0).map(|c| *c as u8 as char))
}

Upvotes: 2

noshusan
noshusan

Reputation: 313

you can create std::ffi::CStr from a pointer but you have to use unsafe keyword.Like this

use std::ffi::CStr;
//use std::os::raw::c_char;

#[repr(C)]
pub struct FFIStruct {
    pub id: [::std::os::raw::c_char; 256usize],
    pub description: [::std::os::raw::c_char; 256usize],
}


fn get_struct() -> Option<FFIStruct> {
    println!("cheating");
    None
}
pub fn main() {
    match get_struct() {
        Some(thing) => 
            println!("Got id:{:?}",unsafe{CStr::from_ptr(thing.id.as_ptr())}),

        None => (),
    }
}

you can also convert CStr into String by using this method

CStr::from_ptr(thing.id.as_ptr()).to_string_lossy()

Upvotes: 1

Shepmaster
Shepmaster

Reputation: 430604

C strings that you don't own should be translated using CStr, not CString. You can then convert it into an owned representation (CString) or convert it into a String:

extern crate libc;

use libc::c_char;
use std::ffi::CStr;

pub fn main() {
    let id = [0 as c_char; 256];
    let rust_id = unsafe { CStr::from_ptr(id.as_ptr()) };
    let rust_id = rust_id.to_owned();
    println!("{:?}", rust_id);
}

You should also use the libc crate for types like c_char.

Upvotes: 11

Related Questions