调用从 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);
}