передача двойного указателя С++ на python

Я мог бы передать одномерный массив в python, как показано ниже. и мне интересно, могу ли я передать массив двойных указателей С++ в python, используя ctypes, numpy.

test.cpp:

#include <stdio.h>
extern "C" void cfun(const void * indatav, int rowcount, int colcount, void * outdatav);

void cfun(const void * indatav, int rowcount, int colcount, void * outdatav) {
    //void cfun(const double * indata, int rowcount, int colcount, double * outdata) {
    const double * indata = (double *) indatav;
    double * outdata = (double *) outdatav;
    int i;
    puts("Here we go!");
    for (i = 0; i < rowcount * colcount; ++i) {
        outdata[i] = indata[i] * 4;
    }
    puts("Done!");
}

test.py:

import numpy
import ctypes

indata = numpy.ones((5,6), dtype=numpy.double)
outdata = numpy.zeros((5,6), dtype=numpy.double)
lib = ctypes.cdll.LoadLibrary('./ctest.so')
fun = lib.cfun
# Here comes the fool part.
#fun(ctypes.c_void_p(indata.ctypes.data), ctypes.c_void_p(outdata.ctypes.data))

fun(ctypes.c_void_p(indata.ctypes.data), ctypes.c_int(5), ctypes.c_int(6),
    ctypes.c_void_p(outdata.ctypes.data))


print 'indata: %s' % indata
print 'outdata: %s' % outdata

person wonjun    schedule 09.01.2012    source источник
comment
Это хак, которому меня научили, но почему бы просто не передавать указатели как длинные целые числа?   -  person Pavan Yalamanchili    schedule 09.01.2012
comment
потому что тип может быть двойным.. и т.д. не только целочисленным.   -  person wonjun    schedule 09.01.2012
comment
Указатели всегда могут быть представлены как длинные целые числа. а затем вернуться к любому типу, который вы хотите.   -  person Pavan Yalamanchili    schedule 16.01.2012


Ответы (1)


Вот способ. Я не видел хорошего способа использовать numpy с double **.

test.cpp (Windows)

#include <stdio.h>

extern "C" __declspec(dllexport) void cfun(const double ** indata, int rowcount, int colcount, double ** outdata) {
    for (int i = 0; i < rowcount; ++i) {
        for (int j = 0; j < colcount; ++j) {
            outdata[i][j] = indata[i][j] * 4;
        }
    }
}

test.py

import numpy
import ctypes

# Allocate array of double*
indata = (ctypes.POINTER(ctypes.c_double) * 5)()
for i in range(5):
    # Allocate arrays of double
    indata[i] = (ctypes.c_double * 6)()
    for j in range(6):
        indata[i][j] = 1.0

outdata = (ctypes.POINTER(ctypes.c_double) * 5)()
for i in range(5):
    outdata[i] = (ctypes.c_double * 6)()
    for j in range(6):
        outdata[i][j] = 1.0

lib = ctypes.cdll.LoadLibrary('test')
fun = lib.cfun

def dump(a,rows,cols):
    for i in range(rows):
        for j in range(cols):
            print a[i][j],
        print

dump(indata,5,6)
fun(ctypes.byref(indata),5,6,ctypes.byref(outdata))
dump(outdata,5,6)

Выход

1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0
4.0 4.0 4.0 4.0 4.0 4.0
4.0 4.0 4.0 4.0 4.0 4.0
4.0 4.0 4.0 4.0 4.0 4.0
4.0 4.0 4.0 4.0 4.0 4.0
4.0 4.0 4.0 4.0 4.0 4.0
person Mark Tolonen    schedule 09.01.2012
comment
У меня возникла ошибка при создании файла .so test.cpp:4:1: ошибка: ожидается конструктор, деструктор или преобразование типа перед токеном ‘(’ - person wonjun; 09.01.2012
comment
он отлично работает без __declspec(dllexport). спасибо, а в фортране многомерный массив можно передать напрямую с помощью numpy, верно? fwrap.. на самом деле я ищу передаваемый массив среди python‹-›c,c++‹-›fortran. - person wonjun; 09.01.2012
comment
Да, __declspec(dllexport) специфичен для Windows для экспорта функции из динамической библиотеки. Код, который вы разместили, работает как есть (с небольшими модами для Windows, для меня) с двойным указателем и многомерным массивом. Однако вам не нужен весь этот кастинг. В чем именно заключается ваш вопрос? - person Mark Tolonen; 09.01.2012
comment
Я не касался Fortran в течение многих лет, поэтому не могу помочь. Замечу, что если вы напишете исходную функцию C++ с double* вместо void*, вы сможете передать _____.ctypes.data напрямую, без оболочек ctypes.c_void_p. Вы также можете передать 5,6 вместо ctypes.c_int(5),ctypes.c_int(6). - person Mark Tolonen; 09.01.2012
comment
Есть ли способ передать этот массив с помощью numpy? Я хочу использовать numpy не только с помощью ctypes. - person wonjun; 09.01.2012
comment
Не то, чтобы я знал, если вы вынуждены вызывать существующую функцию, которая принимает double**. Вы можете написать функцию преобразования для преобразования многомерного массива numpy в double **. - person Mark Tolonen; 09.01.2012