I am using a C API (in particular MPI_Init
) that needs int argc, char **argv
. I am trying to generate an equivalent argc, argv
with the following code:
let argc = std::env::args().len() as c_int;
let c_strs: ~[CString] = std::env:args().map(|s: & &str| s.to_c_str());
let mut argv: ~[*c_char] = c_strs.map(|c: &CString| c.with_ref(|ptr| ptr));
if null_terminate {
argv.push(std::ptr::null());
}
By adapting this discussion on Github.
It fails with:
error: expected type, found `~`
src/lib.rs:37 let c_strs: ~[CString] = std::env::args().map(|s: & &str| s.to_c_str());
^
I got rid of the ~
and then it could not find to_c_str()
and was unsure what to replace to_c_str
with, to_raw()
(for instance) failed.
Does anyone know of a way to convert Args
to a more C friendly format?
My answer works with the current stable Rust (1.5) and probably with beta and nightly.
The following Rust code calls the foo(argc, argv)
function implemented in C. The signature of foo
is very similar to a main
function.
extern crate libc;
use libc::c_char;
use libc::c_int;
use std::ffi::CString;
#[link(name="foo")]
extern "C" {
fn foo(argc: c_int, argv: *const *const c_char);
}
fn main() {
// create a vector of zero terminated strings
let args = std::env::args().map(|arg| CString::new(arg).unwrap() ).collect::<Vec<CString>>();
// convert the strings to raw pointers
let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();
unsafe {
// pass the pointer of the vector's internal buffer to a C function
foo(c_args.len() as c_int, c_args.as_ptr());
};
}
Note, that the C side only borrows the pointers to the strings. If you want to store them, use strdup()
on them.
I also used unwrap()
on CString
instances. If your string contains 0 bytes, it will return an error, see https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#method.new.
Proof:
I put this code into a cargo project, and added libc
as a dependency.
The foo()
function looks like this:
#include <stdio.h>
void foo(int argc, char* argv[]) {
int i;
for (i = 0; i < argc; i++) {
printf("argv[%d]: %s\n", i, argv[i]);
}
}
I compiled this code with:
gcc foo.c -o libfoo.so -shared -fPIC
Then copied libfoo.so
under target/debug/deps
(just to be in the library search path). Then I run my cargo project:
$ cargo run the quick brown fox
Compiling args v0.1.0 (file:///home/tibi/Codes/Rust/argv/args)
Running `target/debug/args the quick brown fox`
argv[0]: target/debug/args
argv[1]: the
argv[2]: quick
argv[3]: brown
argv[4]: fox
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With