Created
February 12, 2021 05:31
-
-
Save iskakaushik/1c5b8aa75c77479c33c4320913eebef6 to your computer and use it in GitHub Desktop.
Transfer rust vec to c array strings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::ffi::CString; | |
use std::os::raw::{c_char, c_int}; | |
use std::{ptr, mem}; | |
#[no_mangle] | |
unsafe extern "C" fn get_strings(outlen: *mut c_int) -> *mut *mut c_char { | |
let mut v = vec![]; | |
// Let's fill a vector with null-terminated strings | |
v.push(CString::new("Hello").unwrap()); | |
v.push(CString::new("World").unwrap()); | |
v.push(CString::new("!").unwrap()); | |
// Turning each null-terminated string into a pointer. | |
// `into_raw` takes ownershop, gives us the pointer and does NOT drop the data. | |
let mut out = v | |
.into_iter() | |
.map(|s| s.into_raw()) | |
.collect::<Vec<_>>(); | |
// Make sure we're not wasting space. | |
out.shrink_to_fit(); | |
assert!(out.len() == out.capacity()); | |
// Get the pointer to our vector. | |
let len = out.len(); | |
let ptr = out.as_mut_ptr(); | |
mem::forget(out); | |
// Let's write back the length the caller can expect | |
ptr::write(outlen, len as c_int); | |
// Finally return the data | |
ptr | |
} | |
#[no_mangle] | |
unsafe extern "C" fn free_string_array(ptr: *mut *mut c_char, len: c_int) { | |
let len = len as usize; | |
// Get back our vector. | |
// Previously we shrank to fit, so capacity == length. | |
let v = Vec::from_raw_parts(ptr, len, len); | |
// Now drop one string at a time. | |
for elem in v { | |
let s = CString::from_raw(elem); | |
mem::drop(s); | |
} | |
// Afterwards the vector will be dropped and thus freed. | |
} | |
/* | |
// The C code calling into our Rust part: | |
#include <stdio.h> | |
char** get_strings(int* outlen); | |
void free_string_array(char **ptr, int len); | |
int main(int argc, char** argv) | |
{ | |
int len; | |
char** s = get_strings(&len); | |
for (int i=0; i<len; i++) { | |
printf("String %d: %s\n", i, s[i]); | |
} | |
free_string_array(s, len); | |
return 0; | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
OK, looks like the returned value must be used. But this should work: