如何将C中的双数组转换为python列表?

时间:2014-10-11 08:34:39

标签: python c

我的C代码:

#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结构,我该怎么办?

3 个答案:

答案 0 :(得分:2)

你可以用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]

答案 1 :(得分:0)

你可以使用连接两种语言的函数。

这是一篇展示它的帖子 SWIG C-to-Python Int Array

答案 2 :(得分:0)

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

如果您打算将C代码公开给多种语言,那么SWIG很不错。如果你只打算将你的C暴露给Python,那可能有点过分了。

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

相关问题