63

ああ、私の言葉は私はばかです。 関数を呼び出すときに、2番目と3番目の引数を単に省略していました。馬鹿のように。それが私ですから。元のばかげた質問は次のとおりです。

これは非常に一般的なことのように思えますが、関連するチュートリアルが見つからず、自分でそれを理解することについて無知Numpyですctypes

ファイルにC関数がありますctest.c

#include <stdio.h>

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] * 2;
    }
    puts("Done!");
}

(ご想像のとおり、私はもともと引数をvoidではなくdouble *として持っていましたが、Python側で何をすべきか理解できませんでした。確かにそれらを元に戻したいのですが、私はそれが機能する限り。)

私はそれから共有ライブラリを作成します。gcc -fPIC -shared -o ctest.so ctest.c

次に、Pythonで、いくつかのnumpy配列があり、それらをC関数に渡します。1つは入力として、もう1つは出力として渡します。

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))

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

これはエラーを報告しませんが、出力します

>>> Here we go!
Done!
indata: [[ 1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.]]
outdata: [[ 0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.]]

outdata配列は変更されません。実際、関数を再度呼び出すと、セグメンテーション違反が発生します。それは私を驚かせません-私は本当に私がここで何をしているのか分かりません。誰かが私を正しい方向に向けることができますか?

4

2 に答える 2

84

元の質問に対する直接の答えではありませんが、関数を呼び出すためのはるかに便利な方法があります。まず、プレーンCで行うのとまったく同じように、C関数のプロトタイプを作成します。必要がないためrowcountcolcount個別に作成します。これらを1つのsizeパラメーターにまとめます。

void cfun(const double *indatav, size_t size, double *outdatav) 
{
    size_t i;
    for (i = 0; i < size; ++i)
        outdatav[i] = indatav[i] * 2.0;
}

Now define the ctypes prototype in the following way:

import ctypes
from numpy.ctypeslib import ndpointer
lib = ctypes.cdll.LoadLibrary("./ctest.so")
fun = lib.cfun
fun.restype = None
fun.argtypes = [ndpointer(ctypes.c_double, flags="C_CONTIGUOUS"),
                ctypes.c_size_t,
                ndpointer(ctypes.c_double, flags="C_CONTIGUOUS")]

Now, calls to your function will be really convenient:

indata = numpy.ones((5,6))
outdata = numpy.empty((5,6))
fun(indata, indata.size, outdata)

You could also define a wrapper to make this even more convenient:

def wrap_fun(indata, outdata):
    assert indata.size == outdata.size
    fun(indata, indata.size, outdata)
于 2011-05-03T10:16:43.460 に答える
21

4つの引数すべてをC関数に渡すだけです。Pythonコードを次の場所から変更します。

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))
于 2011-05-02T23:21:17.053 に答える