Delphi编写DLL的数组参数传递及跨语言(如Python)调用问题
问题根源分析
- 错误1:Delphi端
array_out和size_array_out都是按值传递的形参,修改形参只会改动栈上的副本,不会对外部传入的实际参数生效 - 错误2:你使用了Delphi特有的托管动态数组
TArray = Array of Double作为中间存储,这类数组的内存由Delphi runtime自动管理,函数执行结束后就会被释放,即使把地址赋值给array_out,返回给Python的也是野指针,完全无法使用 - 错误3:你没有直接操作Python端预先分配的
data_out内存,而是把值写到了Delphi自己分配的动态数组里,外部自然读取不到修改结果
修正方案
1. Delphi端代码修正
核心逻辑是直接操作传入的指针指向的内存,不要用Delphi特有托管类型做跨语言传递:
library Delphi_Library; uses System.SysUtils; function AddIntegers(const _a, _b: integer): integer; stdcall; begin Result := _a + _b; end; function ReturnArray(array_in: PDouble; size_array_in: Integer; array_out: PDouble; var size_array_out: Integer): Double; stdcall; var i: Integer; copy_count: Integer; begin Result := 0; // 先判断输出缓冲区长度是否足够 if size_array_out < size_array_in then begin // 不足时返回需要的长度,外部重新分配内存后再调用 size_array_out := size_array_in; Exit; end; // 计算实际复制的元素数 copy_count := size_array_in; size_array_out := copy_count; // 直接往传入的输出缓冲区写数据 for i := 0 to copy_count - 1 do begin array_out^ := array_in^; Result := array_in^; // 最后一个元素就是返回值 Inc(array_in); Inc(array_out); end; end; exports AddIntegers, ReturnArray; begin end.
注意:如果需要兼容纯C调用约定,把
var size_array_out: Integer改成size_array_out: PInteger,代码里操作size_array_out^即可,和var参数本质是一样的。
2. Python端代码修正
不需要给数组套POINTER,ctypes的数组本身传递时就会自动转成首元素指针,需要修改的长度参数要传引用:
import ctypes Dll = ctypes.WinDLL('Delphi_Library') # 先测试整数加法 a = ctypes.c_int(5) b = ctypes.c_int(7) c = Dll.AddIntegers(a, b) print("加法结果:", c) # 配置数组函数 ReturnArray = Dll.ReturnArray ReturnArray.restype = ctypes.c_double ReturnArray.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.c_int)] # 准备输入输出数组 data_in = (ctypes.c_double * 8)(*range(32, 40)) data_out = (ctypes.c_double * 8)() # 先分配8个元素的缓冲区 num_in = ctypes.c_int(8) num_out = ctypes.c_int(8) print('调用前输入:', list(data_in)) print('调用前输出:', list(data_out)) retval = ReturnArray(data_in, num_in, data_out, ctypes.byref(num_out)) print('返回值:', retval) print('实际输出长度:', num_out.value) print('调用后输出:', list(data_out))
扩展到二维数组/矩阵的方案
跨语言传递二维数组统一约定为行优先的连续内存块,传递参数约定为:
- 矩阵首元素指针
PDouble - 行数
Integer - 列数
Integer
比如接收二维数组的Delphi函数可以这么写:
function ProcessMatrix(matrix: PDouble; rows: Integer; cols: Integer): Double; stdcall; var i, j: Integer; current_val: Double; begin for i := 0 to rows - 1 do for j := 0 to cols - 1 do begin current_val := matrix^; // 这里写你的矩阵处理逻辑 Inc(matrix); end; // 返回计算结果 end;
Python端传递二维数组的时候,先把二维列表拉平成一维连续数组再传递即可。
内容的提问来源于stack exchange,提问作者pjuergens
相关产品推荐
相关产品推荐

