Converting &str to *const c_char

I've the below function:

use std::os::raw::{c_char};
use std::ffi::{CString, CStr};

pub extern fn rust_greeting(to: *const c_char) -> *mut c_char {
    let c_str = unsafe { CStr::from_ptr(to) };
    let recipient = match c_str.to_str() {
        Err(_) => "there",
        Ok(string) => string,
    };
    CString::new("Hello ".to_owned() + recipient).unwrap().into_raw()
}

And want to call it from the below function:

pub fn hi(to :&str) -> String {

// let returned_value = rust_greeting(to);   // <- how to make this


// Below is to convert the returned `*mut c_char` into `&str` so I can return it back.
    let c_str = unsafe { CStr::from_ptr(returned) };
    let recipient = match c_str.to_str() {
        Err(_) => "there",
        Ok(string) => string,
    };

format!("Hi {}", recipient)
}

How can I convert the &str into *const c_char ?

I tried using:

let k = rust_greeting(to.as_ptr());

But got the below error:

error[E0308]: mismatched types
  --> src/lib.rs:24:27
   |
24 |     let k = rust_greeting(to.as_ptr());
   |                           ^^^^^^^^^^^ expected i8, found u8
   |
   = note: expected type `*const i8`
              found type `*const u8`

error: aborting due to previous error
1 Like

Consider yourself very lucky that you got this error, and that c_char is i8 instead of u8 on your system. This would have been undefined behavior if it compiled.

Rust strings are not null-terminated. C strings are. This means that, if you have a &str in Rust, you need to copy it into a new buffer and add a null terminator. You can do this by constructing a CString.

4 Likes

I got it work as below:

    let c_str = CString::new(to).unwrap();
    let c_world: *const c_char = c_str.as_ptr() as *const c_char;
7 Likes