2014-10-11 165 views
2

我的C代码:如何将C中的double数组转换为python列表?

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
double * Make_A(){ 
    double A[2]; 
    A[0]=0.00001; 
    double *p=(double *)&A; 
    return p; 
} 

,并有我的Python代码:

from ctypes import * 
lib_cpp = cdll.LoadLibrary('./test.so') 

C程序返回一个双数组指针,而我得到的Python程序的指针,我想转换的C数组到python列表或其他python结构,我该怎么办?

+0

你回答在这里 http://stackoverflow.com/questions/5778500/swig-c-to-python-int-array – Gabriel 2014-10-11 09:03:24

回答

1

你可以做你与ctypes的要求是什么,但是你C代码就是有一些不足之处。最大的问题是这样的:

double A[2]; 

这将创建2个双打堆栈上的阵列。当你使用return p;这有效地结束了返回一个指向栈上数组的指针。由于当你的函数退出时,堆栈将放松,你不能再依靠指针的有效性。如果你想要一个2双打数组,使用malloc来创建它们,然后返回一个指向该数组的指针。所以这段代码将工作:

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

double * Make_A(){ 
    /* Use Malloc to create an array of 2 doubles */ 
    double *A = malloc(2 * sizeof(double)); 
    A[0] = 0.00001; 
    A[1] = 42.0; 
    return A; 
} 

除了你应该创建一个可以从Python中调用一个函数来释放你的C面创造任何指针:

/* Create a function that can free our pointers */ 
void freeptr(void *ptr) 
{ 
    free(ptr); 
} 

随着我们的C代码创建我们可以使用ctypes来加载我们的共享对象并调用我们的函数。

import ctypes 
lib_cpp = ctypes.CDLL('./test.so') 

# Make_A returns a pointer to two doubles 
lib_cpp.Make_A.restype = ctypes.POINTER(ctypes.c_double * 2) 

# freeptr takes one argument that is a void pointer 
lib_cpp.freeptr.argtype = ctypes.c_void_p 
# freeptr return void (no parameters) 
lib_cpp.freeptr.restype = None 

# Call Make_A and retrieve a double array pointer 
darrayptr = lib_cpp.Make_A() 
# Convert the array pointer contents to a Python list 
floatlist = [x for x in darrayptr.contents] 

# We need to free our pointer since Python won't know to 
# do it for us. Similar to C where we must free anything we 
# malloc. 
lib_cpp.freeptr(darrayptr) 

你可以在Python documentation;找到ctypes的材料;一些sample code给你一些想法;和这tutorial

如果您不想创建一个完整的Python模块,您还可以创建一个共享对象,该对象使用Python数据类型并返回一个包含浮点列表的PyObject。在PyList的信息可以在这个documentation和文档的PyFloat类型可发现在这个documentation发现:

的PyObject * PyList_New(Py_ssize_t LEN)

返回值:新基准。

成功返回长度为len的新列表,失败时返回NULL。

然后,您可以前所有其他包括添加这个例子C代码

#include <Python.h> 

然后你就可以添加以下代码:

PyObject* getList(void) 
{ 
    PyObject *dlist = PyList_New(2); 
    PyList_SetItem(dlist, 0, PyFloat_FromDouble(0.00001)); 
    PyList_SetItem(dlist, 1, PyFloat_FromDouble(42.0)); 

    return dlist; 
} 

共享对象可以在安装了软件包python-dev(或python-devel)的大多数* nix类型的系统上使用这样的命令来构建:

gcc -c -Wall -Werror -fPIC `python-config --cflags` test.c 
gcc -shared -o test.so test.o `python-config --ldflags` 
在Python

现在可以,你可以做类似的代码我们前面有,但我们现在可以使用Python列出了更直接:

import ctypes 
lib_cpp = ctypes.CDLL('./test.so') 

# getList returns a PyObject 
lib_cpp.getList.restype = ctypes.py_object 

# Now call it and do something with the list 
mylist = lib_cpp.getList() 
print(mylist) 

输出看起来是这样的:

[1e-05, 42.0] 
0

ctypes可能会有点慢。也很脆弱。如果你在C中花费了很多时间,并且不跨C-Python边界,那么性能很好。但仍然脆弱。

如果您打算将C代码暴露给多种语言,那么SWIG很不错。如果您只打算将C暴露给Python,那可能是过度杀伤。

如果你想要快速方便的东西,你可以看看Cython。 Cython是Python的一种方言,它允许您自由地混合使用Python和C数据类型(并且在定义类时必须声明实例变量的类型)。您使用的C数据类型越多,代码运行得越快 - 但要注意(隐式)类型转换 - 它们可能会成为性能杀手。

相关问题