Convert a C struct to Rust, FFI

Hi!

I writing a crates that is linked to an external C library. To pass calls to that library I use FFI.

The API of the C lib is straightforward: one function that return a C struct, composed by an int32 and a char * :

typedef struct  s_nl_data {
    char        *essid;
    int32_t     signal;
}               t_nl_data;

/* API */
t_nl_data       *get_data();

And this is my Rust code:

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

#[derive(Debug)]
#[repr(C)]
pub struct LnData {
    signal: c_int,
    essid: *const c_char,
}

#[derive(Debug)]
pub struct SafeData {
    signal: i32,
    essid: String,
}

#[link(name = "nl_data", kind = "static")]
extern "C" {
    pub fn get_data() -> *const LnData;
}

pub fn data() -> SafeData {
    unsafe {
        let nl_data = get_data();
        SafeData {
            signal: (*nl_data).signal,
            essid: CStr::from_ptr((*nl_data).essid)
                .to_string_lossy()
                .into_owned(),
        }
    }
}

I'm struggle to convert that C struct in a Rust safe struct using the corresponding types.
The signal is normally a value between -1 and 100.
But when I print/debug the value of the struct I receive I receive:

LnData {
    signal: -690688272,  // the value is just wrong
    essid: 0x0000000000000047,
}

followed by a SIGSEGV..

I don't understand what I'm doing wrong.

Not that I tested the library with a dummy C binary and it works well. (Even valgrind clean)

The order of the fields is swapped in the Rust struct versus the C struct. Here, essid comes first:

typedef struct  s_nl_data {
    char        *essid;
    int32_t     signal;
}               t_nl_data;

But here, signal comes first:

pub struct LnData {
    signal: c_int,
    essid: *const c_char,
}

Oh my fucking god, wasted one night and a couple more hours on this :rofl:

Thanks!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.