代码之家  ›  专栏  ›  技术社区  ›  Jason Sundram Red Alert

通过SWIG从C到Python:无法获取void**参数来保存其值

  •  8
  • Jason Sundram Red Alert  · 技术社区  · 17 年前

    我有一个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 ,但我找不到任何好的例子来说明如何将指针传递给指针并检索其值。

    我认为正确的方法是使用类型映射,所以我定义了一个在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)
    

    呼叫测试后。Operation(),p始终保持其初始值None。

    非常感谢您在SWIG中找出正确的方法。否则,我可能只会在C代码周围编写一个C++包装器,以阻止Python处理指针。然后包起来 带有SWIG的包装。谁来阻止我!

    编辑:

    多亏了 Jorenko

    % 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代码中,测试。GetFieldValue(p)返回乱码,但test.gfv(p)会返回正确的值。我在void*的类型映射中插入了调试代码,两者都有相同的p值!电话有什么想法吗?

    我决定使用ctypes。容易多了。

    2 回复  |  直到 9 年前
        1
  •  7
  •   Jorenko    17 年前

    但是,如果你决心使用swig,你需要做的就是为 void** void* :

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

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

    编辑:

    无效* 无效*

    %typemap (in) void*
    {
        $1 = PyCObject_AsVoidPtr($input);
    }
    
        2
  •  4
  •   theller    17 年前

    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)