< 返回版块

eweca 发表于 2021-01-15 13:25

请教大家一个关于调用cdll的问题。如下,我封装了一个C++函数,并暴露出C接口,头文件如下:

#pragma once
#ifdef __cplusplus
extern "C" {
#endif

    typedef struct {
        int row;
        int col;
        double data;
    } cdef_matrix;

    typedef struct {
        int row;
        double data;
    } cdef_vector;

    typedef struct {
        int size;
        cdef_vector* data;
    } cdef_ret_vector;

    extern "C" __declspec(dllimport) cdef_ret_vector* spsolver_LU(cdef_matrix* A, int A_size, cdef_vector* B, int B_size, int row, int col);

#ifdef __cplusplus
}
#endif

rust这边这么构造:

use libloading::{Library, Symbol};
use sprs::CsMat;

fn main() {
    spsolver();
}

type SPSolverLU = unsafe fn(*mut cdef_matrix, i32, *mut cdef_vector, i32, i32, i32) -> *mut cdef_ret_vector;
#[repr(C)]
pub struct cdef_matrix {
    row: i32,
    col: i32,
    data: f64,
}

#[repr(C)]
#[derive(Debug)]
pub struct cdef_vector {
    row: i32,
    data: f64,
}

#[repr(C)]
pub struct cdef_ret_vector {
    size: i32,
    data: *mut cdef_vector,
}

fn spsolver() {
    let lib = Library::new("spsolver_for_rust.dll").unwrap();
    unsafe {
        let mut a00 = cdef_matrix{row: 0, col: 0, data: 1.0};
        let mut a01 = cdef_matrix{row: 0, col: 1, data: 2.0};
        let mut a10 = cdef_matrix{row: 1, col: 0, data: 3.0};
        let mut a11 = cdef_matrix{row: 1, col: 1, data: 4.0};
        let mut a = vec![a00, a01, a10, a11];

        let mut b0 = cdef_vector{row: 0, data: 17.0};
        let mut b1 = cdef_vector{row: 1, data: 39.0};
        let mut b = vec![b0, b1];

        let func: Symbol<SPSolverLU> = lib.get(b"spsolver_LU").unwrap();
        let x = func(a.as_mut_ptr(), 4, b.as_mut_ptr(), 2, 2, 2);
        
        // rebuild results as Vec<cdef_veoctr>
        // A: [[1, 2], [3, 4]] B: [17, 39]   ->   AX = B -> X:[5, 6] 
        let x_len = (*x).size as usize;
        let x_cap = x_len;
        let x_ptr = (*x).data;
        let rebuilt_x = Vec::from_raw_parts(x_ptr, x_len, x_cap);
        println!("{:?}", rebuilt_x);
    }
}

如上程序是可以运行出正确结果的,但实际上我只需要返回一个结构体cdef_ret_vector,而不是一个结构体数组cdef_ret_vector*。但是假如我修改两边的定义,不返回指针而是直接返回一个结构体cdef_ret_vector的话。就各种error: .....access violation。这是什么原因呢?每次都定义一个结构体数组来返回,逼死强迫症。

貌似不calloc而是直接传结构体的指针也会失败?我有个猜想,是不是rust分配给dll的栈在退出后会直接清除?所以导致只有分配到堆上的数据的指针能被传回来正常使用?

评论区

写评论
作者 eweca 2021-01-15 17:54

所以遇到传结构体的地方,统统传指针会比较好是么。但是有了指针之后,访问结构体成员倒是很正常,哎,总之有点纳闷。

--
👇
c5soft: 这个问题应该是涉及到Rust变量在内存中占据的空间大小与变量的生命周期的问题,传指针应该是借用关系,并且指针占用空间大小是固定的,处理起来简单,传递结构体的话那就复杂了,双方需要仔细协商。

c5soft 2021-01-15 16:50

这个问题应该是涉及到Rust变量在内存中占据的空间大小与变量的生命周期的问题,传指针应该是借用关系,并且指针占用空间大小是固定的,处理起来简单,传递结构体的话那就复杂了,双方需要仔细协商。

1 共 2 条评论, 1 页