调用从 Rust 接收命令行参数的 C++ 函数时出现问题
Problem with calling C++ function that receive command line arguments from Rust
我正在尝试从 Rust 调用 C++ 函数。该函数假设接收命令行参数然后打印它。我使用 cmake 将 C++ 代码编译为静态存档。我写了一个 build.rs 脚本来引用静态库位置并建立静态链接。
// library.cpp
#include "library.h"
#include <iostream>
extern "C"{
void print_args(int argc, char *argv[]){
std::cout << "Have " << argc << " arguments:" << std::endl;
std::cout<<argv<<std::endl;
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
}
}
//library.h
extern "C"{
void print_args(int argc, char *argv[]);
}
//build.rs
pub fn main(){
println!("cargo:rustc-link-search=.../cmake-build-debug"); //library.a directory
println!("cargo:rustc-link-lib=static=stdc++");
println!("cargo:rustc-link-lib=static=library");
}
//main.rs
#[link(name = "library", kind = "static")]
extern "C" {
pub fn print_args(args: c_int, argsv: *const c_char);
}
fn main() {
let args = std::env::args()
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<CString>>();
let args_len: c_int = args.len() as c_int;
let c_args_ptr = args.as_ptr() as *const c_char;
unsafe { print_args(args_len, c_args_ptr) };
}
当运行命令 cargo run "10" "11"
的rust代码。它只能打印第一个参数,即程序名称,然后是错误
error: process didn't exit successfully: target\debug\static_library_binding_test.exe 10 11 (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
出现。
就是输出rustmain.rs
Have 3 arguments:
target\debug\static_library_binding_test.exe
error: process didn't exit successfully: `target\debug\static_library_binding_test.exe 10 11` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
所以,我需要知道如何将命令行参数从 rust 传递给 c++ 函数。
问题出在这段代码中:
let args = std::env::args()
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<CString>>();
// ...
let c_args_ptr = args.as_ptr() as *const c_char;
这将创建一个包含 CString
个对象的向量,然后您可以将其转换为一个指针数组。但是 CString
由两个字大小的值组成,一个指针和一个长度,并且不能被重新解释为单个指针。要获得 print_args()
期望的实际指针数组,您需要将它们收集到一个单独的向量中:
let args = std::env::args()
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<CString>>();
let arg_ptrs: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
let args_len: c_int = args.len() as c_int;
unsafe { print_args(args_len, arg_ptrs.as_ptr()) };
请注意,您需要将 print_args
声明为指向指针的指针,就像在 C++ 中一样(const char *argv[]
只是 const char **argv
的糖):
#[link(name = "library", kind = "static")]
extern "C" {
pub fn print_args(args: c_int, argsv: *const *const c_char);
}
我正在尝试从 Rust 调用 C++ 函数。该函数假设接收命令行参数然后打印它。我使用 cmake 将 C++ 代码编译为静态存档。我写了一个 build.rs 脚本来引用静态库位置并建立静态链接。
// library.cpp
#include "library.h"
#include <iostream>
extern "C"{
void print_args(int argc, char *argv[]){
std::cout << "Have " << argc << " arguments:" << std::endl;
std::cout<<argv<<std::endl;
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
}
}
//library.h
extern "C"{
void print_args(int argc, char *argv[]);
}
//build.rs
pub fn main(){
println!("cargo:rustc-link-search=.../cmake-build-debug"); //library.a directory
println!("cargo:rustc-link-lib=static=stdc++");
println!("cargo:rustc-link-lib=static=library");
}
//main.rs
#[link(name = "library", kind = "static")]
extern "C" {
pub fn print_args(args: c_int, argsv: *const c_char);
}
fn main() {
let args = std::env::args()
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<CString>>();
let args_len: c_int = args.len() as c_int;
let c_args_ptr = args.as_ptr() as *const c_char;
unsafe { print_args(args_len, c_args_ptr) };
}
当运行命令 cargo run "10" "11"
的rust代码。它只能打印第一个参数,即程序名称,然后是错误
error: process didn't exit successfully: target\debug\static_library_binding_test.exe 10 11 (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
出现。
就是输出rustmain.rs
Have 3 arguments:
target\debug\static_library_binding_test.exe
error: process didn't exit successfully: `target\debug\static_library_binding_test.exe 10 11` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
所以,我需要知道如何将命令行参数从 rust 传递给 c++ 函数。
问题出在这段代码中:
let args = std::env::args()
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<CString>>();
// ...
let c_args_ptr = args.as_ptr() as *const c_char;
这将创建一个包含 CString
个对象的向量,然后您可以将其转换为一个指针数组。但是 CString
由两个字大小的值组成,一个指针和一个长度,并且不能被重新解释为单个指针。要获得 print_args()
期望的实际指针数组,您需要将它们收集到一个单独的向量中:
let args = std::env::args()
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<CString>>();
let arg_ptrs: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
let args_len: c_int = args.len() as c_int;
unsafe { print_args(args_len, arg_ptrs.as_ptr()) };
请注意,您需要将 print_args
声明为指向指针的指针,就像在 C++ 中一样(const char *argv[]
只是 const char **argv
的糖):
#[link(name = "library", kind = "static")]
extern "C" {
pub fn print_args(args: c_int, argsv: *const *const c_char);
}