C per Python via SWIG: non è possibile ottenere i parametri ** vuoto per tenere il loro valore

StackOverflow https://stackoverflow.com/questions/540427

  •  22-08-2019
  •  | 
  •  

Domanda

Ho un'interfaccia C che assomiglia a questo (semplificato):

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

che viene utilizzato come segue:

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

Avrete notato che l'operazione () alloca il buffer p, che GetFieldValue interroga p, e che Cleanup libera p. Non ho alcun controllo sull'interfaccia C -. Che il codice è ampiamente utilizzato altrove

Mi piacerebbe chiamare questo codice Python tramite SWIG , ma non sono riuscito a trovare alcuna buoni esempi di come passare un puntatore a un puntatore -. e recuperare il suo valore

Credo che il modo corretto per farlo è con l'uso di typemaps, così ho definito un'interfaccia che farebbe automaticamente dereferenziare p per me sul lato C:

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

Tuttavia, non sono riuscito a ottenere il seguente codice Python per lavorare:

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

Dopo aver chiamato test.Operation (), p sempre mantenuto il suo valore iniziale di None.

Qualsiasi aiuto per capire il modo corretto di fare questo in SWIG sarebbe molto apprezzato. In caso contrario, io sono suscettibili di scrivere solo un wrapper C ++ tutto il codice C che si ferma Python da avere a che fare con il puntatore. E poi avvolgere che involucro con SWIG. Qualcuno mi fermi!

Modifica:

Grazie a Jorenko , ora ho la seguente interfaccia 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);
    }
}

Il codice python che usa questa interfaccia SWIG è la seguente:

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) 

Stranamente, nel codice python, test.GetFieldValue (p) restituisce senza senso, ma test.gfv (p) restituisce il valore corretto. Ho l'inserimento di codice di debug nel typemap per void *, ed entrambi hanno lo stesso valore di p! La chiamata Tutte le idee su questo?

Aggiornamento: Ho deciso di usare ctypes. Molto più facile.

È stato utile?

Soluzione

Sono d'accordo con theller, è necessario utilizzare invece ctypes. E 'sempre più facile che pensare a typemaps.

Ma, se siete morti insieme sull'utilizzo sorso, cosa che devi fare è fare un typemap per void** che restituisce il void* appena allocato:

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

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

Allora il tuo pitone si presenta come:

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

Modifica:

mi aspetto sorso di gestire un semplice void* ARG per valore con grazia da solo, ma solo nel caso, ecco il codice sorso per avvolgere il void* per GetFieldValue () e pulizia ():

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

Altri suggerimenti

Sareste disposti a usare ctypes? Ecco il codice di esempio che dovrebbe funzionare (anche se è non testato):

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top