How to use C `uint8_t*` fill Rust data

I am using Rust ffi with C
I hava Rust struct

use std::os::raw::{c_uchar,c_int,c_char};

#[repr(C)]
#[derive(Debug,Default)]
struct F{
    data:[c_uchar;3],
}

beside in C I have uint8_t*

 uint8_t *d[3] = {"11qweqweqwesdfsdf","hhdfgkshdfjhaskdfh","ksdhf"};

I want to fill data with d

But I don't how to do that. Please help

What do you want data to contain? The first three characters of the first string? Or maybe the first character of each of the 3 strings? Or something else?

data contain like {"11qweqweqwesdfsdf","hhdfgkshdfjhaskdfh","ksdhf"}

That is not going to work. It is declared to contain 3 bytes. If you want to assign the C string pointers to its elements, you can declare it as data: [*const c_uchar; 3].

May be data:[c_uchar; 3] is not right.

I just want to rust own data , C function fill data

If you're OK with copying, then make C pass you the data as borrowed in whatever format it prefers (like the 3 pointers), and then use CStr and convert and copy it to Vec<String>.

C strings are in an unspecified encoding, 0-terminated, owned via C's allocator. Rust's strings track explicit length and use Rust's allocator, so Rust side either has to copy them, or deal with all the C-isms.

Can get a sample demo

It's hard to provide a sample when you don't specify which end is supposed to call which and how.

For starters,

#[repr(C)]
struct F {
    data: [*const c_char; 3],
}

is the Rust equivalent of:

typedef struct {
    char const * data[3];
} F;

So, if C happened to have a pointer to an F (a F *) as a parameter, so as to fill the pointee F with the values of d, you'd simply write, in C:

void init_F (
    F * out_f)
{
 // static
    char const * d[3] = { "11qweqweqwesdfsdf", "hhdfgkshdfjhaskdfh", "ksdhf" };
    for (size_t i = 0; i < 3; ++i) {
        out_f->data[i] = d[i];
    }
}

so as to, from Rust:

extern "C" {
    fn init_F (out_f: *mut F);
}

let mut f: F = F {
    data: [ptr::null_mut(); 3],
};
unsafe {
    init_f(&mut f);
}
// Now you got the three `char const *` pointers inside `f.data`;
// time to get actual string-like stuff:

// Only valid as long as the given FFI / C strings remain valid;
// the lifetime `'c` represents that; although because of the FFI,
// Rust has no idea what the real value of `'c` is, and so this as
// dangerous as the `*const char` just above!
struct GRef<'c> {
    data: [&'c CStr; 3],
}

let g_ref = GRef {
    data: unsafe {
        [
            CStr::from_ptr(f.data[0]),
            CStr::from_ptr(f.data[1]),
            CStr::from_ptr(f.data[2]),
        ]
    },
};

/// Owned / `strdup`-ed version of `GRef`:
#[derive(Debug)]
struct G {
    data: [CString; 3],
}

let g = G {
    data: [
        g_ref.data[0].to_owned(), // `strdup`,
        g_ref.data[1].to_owned(), // `strdup`,
        g_ref.data[2].to_owned(), // `strdup`,
    ],
};

and now, optionally, you'd like to work with UTF-8 encoded strings in Rust (i.e., &str and String):

struct H {
    data: [String; 3],
}

let h = H {
  data: [
    mem::take(&mut g.data[0]).into_string()?,
    mem::take(&mut g.data[1]).into_string()?,
    mem::take(&mut g.data[2]).into_string()?,
  ]
};

and so on and so forth. Hard to give further code snippets without a more concrete example of what you are trying to achieve

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.