tengo una interfaz de C que tiene este aspecto (simplificado):C a través del pitón del TRAGO: no se puede obtener parámetros void ** para mantener su valor
extern bool Operation(void ** ppData);
extern float GetFieldValue(void* pData);
extern void Cleanup(p);
que se utiliza de la siguiente manera:
void * p = NULL;
float theAnswer = 0.0f;
if (Operation(&p))
{
theAnswer = GetFieldValue(p);
Cleanup(p);
}
Observará que Operation() asigna el buffer p, que GetFieldValue consulta p, y que Cleanup libera p. No tengo ningún control sobre la interfaz C, ese código es ampliamente utilizado en otros lugares.
Me gustaría llamar a este código desde Python a través de SWIG, pero no pude encontrar ningún buen ejemplo de cómo pasar un puntero a un puntero y recuperar su valor.
creo que la forma correcta de hacerlo es mediante el uso de typemaps, por lo que define una interfaz que lo haría automáticamente eliminar la referencia de p para mí en el lado C:
%typemap(in) void** {
$1 = (void**)&($input);
}
Sin embargo, no he podido conseguir el siguiente código Python para trabajar:
import test
p = None
theAnswer = 0.0f
if test.Operation(p):
theAnswer = test.GetFieldValue(p)
test.Cleanup(p)
Después de llamar test.Operation(), p siempre mantuvo su valor inicial de Nada.
Cualquier ayuda para averiguar la forma correcta de hacer esto en SWIG sería muy apreciada. De lo contrario, es probable que solo escriba un contenedor C++ alrededor del código C que impida que Python tenga que lidiar con el puntero. Y luego envuelva esa envoltura con SWIG. ¡Que alguien me pare!
Editar:
Gracias a Jorenko, ahora tengo la siguiente interfaz 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);
}
}
El código Python que utiliza esta interfaz SWIG es el siguiente:
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)
Curiosamente, en el código python, test.GetFieldValue (p) devuelve galimatías, pero test.gfv (p) devuelve el valor correcto. He insertado código de depuración en el mapa de tipos para void *, y ambos tienen el mismo valor de p! La llamada ¿Alguna idea sobre eso?
Actualización: He decidido usar ctypes. Más fácil.
1. 'p 'es al mismo tiempo 'vacío **' y 'void *' en el código Python 2. 'Ninguno' es inmutable, por lo tanto' p' (un objeto al que se refiere) no cambiará sin importar qué (aunque puedes unir 'p' a un objeto diferente (usando' = ')). – jfs