2

My C code:

#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;   
}

and there are my python code:

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

the C program return a double array pointer,and I get the pointer in python program,I wanna convert the C array to python list or other python structure,what should I do?

Karl Doenitz
  • 2,220
  • 3
  • 20
  • 38

3 Answers3

4

You can do what you are asking with ctypes, however your C code as is has some deficiencies. The big problem is this:

double A[2];

This creates an array of 2 doubles on the stack. When you use return p; this effectively ends up returning a pointer to an array on the stack. Since the stack will unwind when your function exits you can no longer rely on the pointer being valid. If you want an array of 2 doubles use malloc to create them and then return a pointer to that array. So this code would work:

#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;
}

As well you should create a function that you can call from Python to free any pointers you create on the C side:

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

With our C code created we can use ctypes to load our shared object and call our functions.

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)

You can find material on ctypes in the Python documentation; some sample code to give you some ideas; and this tutorial.

If you don't want to create a full Python module you also have the ability to create a shared object that utilizes Python data types and return a PyObject that contains a list of floats. Information on PyList can be found in this documentation and documentation on the PyFloat type can be found in this documentation:

PyObject* PyList_New(Py_ssize_t len)

Return value: New reference.

Return a new list of length len on success, or NULL on failure.

You can then add this example to your C code before all other includes:

#include <Python.h>

And then you can add this code:

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;
}

The shared object can be built with a command like this on most *nix type systems where the package python-dev (or python-devel) is installed:

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

Now in Python can you can do code similar to what we had earlier, but we can now use Python lists more directly:

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)

The output would look something like:

[1e-05, 42.0]
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
1

ctypes can be a bit slow. Brittle too. If you spend a lot of time in your C, and don't cross the C-Python boundary much, performance is fine. But still brittle.

SWIG is nice if you plan to expose your C code to multiple languages. If you're only planning on exposing your C to Python, it's probably overkill.

If you want something fast and convenient, you might look into Cython. Cython is a dialect of Python that allows you to freely intermix Python and C datatypes (plus you have to declare the types of your instance variables when you define a class). The more C datatypes you use, the faster your code runs - but watch out for (implicit) type conversions - they can be a performance killer.

user1277476
  • 2,871
  • 12
  • 10
0

you can useswig which bridges the two languages.

Here is a post that shows it SWIG C-to-Python Int Array

Community
  • 1
  • 1
Gabriel
  • 3,564
  • 1
  • 27
  • 49