Nathan McMillan
Nathan McMillan

Reputation: 57

Call Rust with arguments

I've been trying to call a Rust function from C with multiple string arguments, but for some reason the only argument that being sent is the first. This is what I've tried:

input.c

extern void print_str(char str1, char str2);

void c_function() {
    scanf("%s %s", str1, str2);
    print_str(str1, str2);
}

lib.rs:

#[no_mangle]
pub extern "C" fn print_str(str1: &str, str2: &str) {
    unsafe {
       libc::printf(str1.as_ptr() as *const libc::c_char);
       libc::printf(str2.as_ptr() as *const libc::c_char);
    }
}

Upvotes: 1

Views: 632

Answers (2)

Nathan McMillan
Nathan McMillan

Reputation: 57

C code:

extern void print_str(char *str1, char *str2);

void c_function() {
   char str1[10];
   char str2[10];
   scanf("%s "%s", str1, str2);
   print_str(str1, str2);
}

Rust code:

#[no_mangle]
pub extern "C" fn print_str(str1: &str, str2: &str) {
    unsafe {
        libc::printf(str1.as_ptr() as *const c_char);
        libc::printf(str2.as_ptr() as *const c_char);
    }
}

Upvotes: -1

Masklinn
Masklinn

Reputation: 42302

First, the code you provide is straight up broken, the C snippet makes absolutely no sense.

Second, your types are completely mismatched.

&str is a Rust type, C has no equivalent builtin type, and it most certainly is not equivalent to a C string, its low-level payload (the underlying buffer) is not even compatible with C strings because Rust strings are not nul-terminated. The compiler literally tells you that:

warning: `extern` fn uses type `str`, which is not FFI-safe
 --> src/lib.rs:2:35
  |
2 | pub extern "C" fn print_str(str1: &str, str2: &str) {
  |                                   ^^^^ not FFI-safe
  |
  = note: `#[warn(improper_ctypes_definitions)]` on by default
  = help: consider using `*const u8` and a length instead
  = note: string slices have no C equivalent

Furthermore, from the C side you're sending a char not even a C string.

So what you're doing here is sending two characters, telling Rust that they're really two rust strings, and then misusing that as two C strings, your code has as many UBs as it has lines.

The Rust function should be taking *mut c_char, and the C extern should be defined as taking two char*.

Upvotes: 3

Related Questions