8

私は次のようなCインターフェースを持っています(簡略化):

extern bool Operation(void ** ppData);
extern float GetFieldValue(void* pData);
extern void Cleanup(p);

これは次のように使用されます。

void * p = NULL;
float theAnswer = 0.0f;
if (Operation(&p))
{
   theAnswer = GetFieldValue(p);
   Cleanup(p);
}

Operation() がバッファ p を割り当て、GetFieldValue が p をクエリし、Cleanup が p を解放することに注意してください。私は C インターフェイスを制御することはできません。そのコードは他の場所で広く使用されています。

SWIGを介して Python からこのコードを呼び出したいのですが、ポインターをポインターに渡し、その値を取得する方法の良い例を見つけることができませんでした。

これを行う正しい方法は typemap を使用することだと思うので、C 側で p を自動的に逆参照するインターフェイスを定義しました。

%typemap(in) void** {
   $1 = (void**)&($input);
}

ただし、次の Python コードを動作させることができませんでした。

import test
p = None
theAnswer = 0.0f
if test.Operation(p):
   theAnswer = test.GetFieldValue(p)
   test.Cleanup(p)

test.Operation() を呼び出した後、p は常に初期値の None を保持していました。

SWIG でこれを行う正しい方法を理解するための助けをいただければ幸いです。それ以外の場合は、C コードの周りに C++ ラッパーを記述して、Python がポインターを処理する必要がないようにする可能性があります。そして、そのラッパーを SWIG でラップします。誰か私を止めて!

編集:

Jorenkoのおかげで、次の SWIG インターフェイスを使用できるようになりました。

% module Test 
%typemap (in,numinputs=0) void** (void *temp)
{
    $1 = &temp;
}

%typemap (argout) void**
{
    PyObject *obj = PyCObject_FromVoidPtr(*$1, Cleanup);
    $result = PyTuple_Pack(2, $result, obj);
}
%{
extern bool Operation(void ** ppData); 
extern float GetFieldValue(void *p); 
extern void Cleanup(void *p);
%} 
%inline 
%{ 
    float gfv(void *p){ return GetFieldValue(p);} 
%} 

%typemap (in) void*
{
    if (PyCObject_Check($input))
    {
        $1 = PyCObject_AsVoidPtr($input);
    }
}

この SWIG インターフェイスを使用する Python コードは次のとおりです。

import test 
success, p = test.Operation()
if success:
   f = test.GetFieldValue(p) # This doesn't work 
   f = test.gvp(p) # This works! 
   test.Cleanup(p) 

奇妙なことに、python コードでは、test.GetFieldValue(p) は意味不明な結果を返しますが、test.gfv(p) は正しい値を返します。void* の typemap にデバッグ コードを挿入しましたが、両方とも p の値は同じです! それについて何かアイデアはありますか?

更新: ctypes を使用することにしました。はるかに簡単です。

4

2 に答える 2

7

代わりに ctypes を使用する必要があります。タイプマップについて考えるよりも常に簡単です。

しかし、swig の使用に固執している場合はvoid**、新しく割り当てられた RETURNS のタイプマップを作成する必要がありvoid*ます。

%typemap (in,numinputs=0) void** (void *temp)
{
    $1 = &temp;
}

%typemap (argout) void**
{
    PyObject *obj = PyCObject_FromVoidPtr(*$1);
    $result = PyTuple_Pack(2, $result, obj);
}

次に、あなたのpythonは次のようになります。

import test
success, p = test.Operation()
theAnswer = 0.0f
if success:
   theAnswer = test.GetFieldValue(p)
   test.Cleanup(p)

編集:

swig は単純な値渡しの引数を適切に処理することを期待していますが、念のため、GetFieldValue() と Cleanup()void*をラップする swig コードを次に示します。void*

%typemap (in) void*
{
    $1 = PyCObject_AsVoidPtr($input);
}
于 2009-02-12T14:46:30.440 に答える
4

ctypes を使用しますか? 以下は、動作するはずのサンプル コードです (ただし、テストはされていません)。

from ctypes import *

test = cdll("mydll")

test.Operation.restype = c_bool
test.Operation.argtypes = [POINTER(c_void_p)]

test.GetFieldValue.restype = c_float
test.GetFieldValue.argtypes = [c_void_p]

test.Cleanup.restype = None
test.Cleanup.argtypes = [c_void_p]

if __name__ == "__main__":
    p = c_void_p()
    if test.Operation(byref(p)):
        theAnswer = test.GetFieldValue(p)
        test.Cleanup(p)
于 2009-02-12T08:39:09.293 に答える