[英]Problems with passing and getting arrays for a C function using ctypes
我正在尝试使用 ctypes 将一个二维数组和一个一维数组从我的 python 代码传递给一个 C 函数,然后这个函数将一个一维数组返回到我的 python 终端。
1-我需要从 python 传递数组,如下所示(我是怎么做的)。 2-可能我没有正确设置参数类型和返回类型。 我一直在寻找很多,但没有解决我的问题。
我的 C 代码名为 Thomas_PYTHON_DLL.c:
#include"stdio.h"
#include"stdlib.h"
#include"Thomas.h"
EXPORT double* Thomas(int dimension, double MatrizTridiagonal[dimension]
[dimension],double vec_b[dimension]){
double* Thomas(int dimension, double MatrizTridiagonal[dimension]
[dimension],double vec_b[dimension]){
double a[dimension];
double b[dimension];
double c[dimension];
double resp[dimension];
double *solution;
solution=(double *) malloc(dimension*sizeof(double));
for(int i=0;i<dimension;i++){resp[i]=vec_b[i];}
for(int i=0;i<dimension;i++){
if(i==0){a[i]=0.0;}
else{
a[i]=MatrizTridiagonal[i][i-1];
}
}
for(int i=0;i<dimension;i++){
b[i]=MatrizTridiagonal[i][i];
}
for(int i=0;i<dimension;i++){
if(i==dimension-1){c[dimension-1]=0.0;}
else{
c[i]=MatrizTridiagonal[i][i+1];
}
}
for(int i=0;i<dimension;i++){
if(i==0){
c[i]=c[i]/b[i];
resp[i]=resp[i]/b[i];
}
else{
c[i]=c[i]/(b[i]-c[i-1]*a[i]);
resp[i]=(resp[i]-a[i]*resp[i-1])/(b[i]-a[i]*c[i-1]);
}
}
for(int i=dimension-1;i>=0;i--){
if(i==dimension-1){
solution[i]=resp[i];
}
else{
solution[i]=resp[i]-c[i]*solution[i+1];
}
}
for(int i=0;i<dimension;i++){printf("x%d=|%0.2f| \n",i,solution[i]);}
return solution;
//free(solution);
}
}
我的 C 代码名为 Thomas.h:
#define EXPORT __declspec(dllexport)
EXPORT double* Thomas(int dimension, double MatrizTridiagonal[dimension]
[dimension],double vec_b[dimension]);
最后是我的 Python 代码,名为 Thomas_Python.py:
from ctypes import *
x=(c_double*5)
Tridiagonal = cdll.LoadLibrary('Thomas_dll.dll')
Tridiagonal.Thomas.restype=POINTER(x)
Tridiagonal.Thomas.argtypes=[c_int,((c_double*5)*5),(c_double*5)]
#arrays that i want to pass to C code
a=((c_double*5)*5)((2,-1,0,0,0),(-1,2,-1,0,0),(0,-1,2,-1,0),(0,0,-1,2,-1),
(0,0,0,-1,2))
b=(c_double*5)(4,2,2,2,4)
r=Tridiagonal.Thomas(5,a,b)
print(r[2])
在上面的代码中,我希望在位置“2”打印数组 r 的值,但打印显示我:
<__main__.c_double_Array_5 object at 0x03A77350>
除了知道如何读取数组值,将整个数组作为列表获取之外,还有很大的帮助。 非常感谢您的帮助和时间,我为我的英语道歉。
提到[Python.Docs]:ctypes - Python 的外部函数库。
您的代码存在许多问题。 以下是一些:
double *Thomas(int dimension, double MatrizTridiagonal[dimension][dimension], double vec_b[dimension])
这样的函数头是如何编译的(因为维度)。 但是,我没有用gcc测试过double*
vs. ctypes.POINTER(ctypes.c_double * 5)
当将数组(尤其是多维 - 因为维度需要在编译时知道)作为函数参数处理时,这意味着它们是从外部传递的,有两种处理方法:
但是,我选择了后一种方法。 我创建了一个虚拟.dll ,其中包含一个计算两个数组的乘积的函数(将一维数组视为只有一列的二维数组)。
dll0.c :
#include <stdlib.h>
#if defined(_WIN32)
# define DLL0_EXPORT_API __declspec(dllexport)
#else
# define DLL0_EXPORT_API
#endif
DLL0_EXPORT_API double *dll0Func0(int dimension, double **arr2D, double *arr1D) {
double *solution = (double*)calloc(dimension, sizeof(double));
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
solution[i] += arr2D[i][j] * arr1D[j];
}
}
return solution;
}
DLL0_EXPORT_API void dealloc(double *ptr) {
free(ptr);
}
脚本0.py :
#!/usr/bin/env python3
import sys
import ctypes
DLL_NAME = "./dll0.dll"
def main():
dim = 5
DoubleArr = ctypes.c_double * dim
DoubleArrArr = DoubleArr * dim
DoublePtr = ctypes.POINTER(ctypes.c_double)
DoublePtrPtr = ctypes.POINTER(DoublePtr)
DoublePtrArr = DoublePtr * dim
dll0 = ctypes.CDLL(DLL_NAME)
dll0Func0 = dll0.dll0Func0
dll0Func0.argtypes = [ctypes.c_int, DoublePtrPtr, DoublePtr]
dll0Func0.restype = DoublePtr
dealloc = dll0.dealloc
dealloc.argtypes = [DoublePtr]
mat = DoubleArrArr(
(2, -1, 0, 0, 0),
(-1, 2, -1, 0, 0),
(0, -1, 2, -1, 0),
(0, 0, -1, 2, -1),
(0, 0, 0, -1, 2),
)
vec = DoubleArr(4, 2, 2, 2, 4)
res = dll0Func0(dim, ctypes.cast(DoublePtrArr(*(ctypes.cast(row, DoublePtr) for row in mat)), DoublePtrPtr), ctypes.cast(vec, DoublePtr))
print("{0:s} returned {1:}".format(dll0Func0.__name__, res))
for i in range(dim):
print("{0:d} - {1:.3f}".format(i, res[i]))
dealloc(res)
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("\nDone.")
这里唯一棘手的是DoublePtrArr 转换,因为2D数组不能直接转换为 double( ** ,而不是类型)指针(我的意思是可以,但是 2 个内存布局不同,所以它会生成Undefined行为,并且最有可能的程序将段错误(访问冲突)),所以每个内阵列在中间对象,这将在随后转换为双(**)指针单独铸造(即该函数需要)。
输出:
cfati@CFATI-5510-0:e:\\Work\\Dev\\StackOverflow\\q057295045]> sopr.bat *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages *** [prompt]> "c:\\Install\\x86\\Microsoft\\Visual Studio Community\\2017\\VC\\Auxiliary\\Build\\vcvarsall.bat" x64 ********************************************************************** ** Visual Studio 2017 Developer Command Prompt v15.9.14 ** Copyright (c) 2017 Microsoft Corporation ********************************************************************** [vcvarsall.bat] Environment initialized for: 'x64' [prompt]> dir /b dll0.c script0.py thomas.c Thomas.h [prompt]> cl /nologo /DDLL dll0.c /link /NOLOGO /DLL /OUT:dll0.dll dll0.c Creating library dll0.lib and object dll0.exp [prompt]> dir /b *.dll dll0.dll [prompt]> "e:\\Work\\Dev\\VEnvs\\py_064_03.07.03_test0\\Scripts\\python.exe" script0.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 dll0Func0 returned <__main__.LP_c_double object at 0x0000026CD4BEC4C8> 0 - 6.000 1 - -2.000 2 - 0.000 3 - -2.000 4 - 6.000 Done.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.