Reading pointer from Rust in C

I'm trying to use Rust with C, by creating DLL and connect it to my C-project. And now, I have some troubles with passing pointers.

I wrote some example and tried to understand this problem:

#[no_mangle]
pub extern fn hex2ascii(hex_len : usize, hex_in: *const u8, ascii_len : &mut usize, ascii_out : *mut c_char) -> *mut c_char {
    let mut out_str = String::new();
    
    unsafe {
        let array = std::slice::from_raw_parts(hex_in, hex_len);
        for i in array
        {
             out_str.push_str(&(format!("0x{:02X?}, ", i)));
        }
        println!("{ }", out_str);

        out_str.pop();
        *ascii_len = out_str.len();
        ascii_out = std::ffi::CString::new(out_str.clone()).unwrap().into_raw();
        return ascii_out;
    }

}

If I try to replace return ascii_out; with return std::ffi::CString::new(out_str.clone()).unwrap().into_raw();, it will work properly. But I want to put pointer in ascii_out and read it in my C-proj.

P.S. Adding a simple test on C++

    unsigned char arr[] = { 0x32, 0x45, 0xab, 0xFF, 0x00, 0x3C };
    size_t size = 0;
    int size2 = sizeof(arr);
    char *out = hex2ascii(size2, arr, &size);
    for (int i = 0; i < size - 1; i++)
    {
        std::cout << out[i];
    }
    std::cout << std::endl;

However, I want to have something like this:

    unsigned char arr[] = { 0x32, 0x45, 0xab, 0xFF, 0x00, 0x3C };
    size_t size = 0;
    int size2 = sizeof(arr);
    char out[255];           // here can be any size
    int rc = hex2ascii(size2, arr, &size, out);
    for (int i = 0; i < size - 1; i++)
    {
        std::cout << out[i];
    }
    std::cout << std::endl;

Upvotes: 3

Views: 571

Answers (1)

Christian
Christian

Reputation: 952

If you got everything to build and link properly the solution you're looking for is inside of std::ptr::copy. It will copy N bytes from source to destination.

"std::ptr::copy is semantically equivalent to C's memmove, but with the argument order swapped."

If you've stumbled across this post, and haven't got linking or compilation to work - I recommend looking at this github repo

Somewhat of a side note - if you know memory isn't overlapping it's recommended to use std::ptr::copy_nonoverlapping instead.

use std::ffi::CString;

use std::os::raw::c_char;

#[no_mangle]
pub extern "C" fn hex2ascii(
    hex_in: *const u8,
    hex_len : usize,
    ascii_len : &mut usize,
    ascii_out : *mut c_char
) -> *mut c_char 
{
    let mut out_str = String::new();
    
    unsafe {
        let array = std::slice::from_raw_parts(hex_in, hex_len);
        for i in array {
             out_str.push_str(&(format!("0x{:02X?}, ", i)));
        }

        out_str.pop();
        *ascii_len = out_str.len();
        let c_str_out = CString::new(out_str).unwrap();

        std::ptr::copy(c_str_out.as_ptr(), ascii_out, *ascii_len); // Copy N bytes to dst from src
        
        return c_str_out.into_raw();
    }
}
// note I changed the parameter order in rust.
// this code reflects those changes.

int main() {
    unsigned char arr[] = { 0x32, 0x45, 0xab, 0xFF, 0x00, 0x3C };
    size_t size = 0;
    int size2 = sizeof(arr);
    char out[255];           // here can be any size
    char * old_way = hex2ascii(arr, size2, &size, out);
    for (int i = 0; i < size - 1; i++)
    {
        std::cout << out[i];
    }
    std::cout << std::endl;
}

Upvotes: 2

Related Questions