代码之家  ›  专栏  ›  技术社区  ›  jtlz2

ctypes:提取C库返回的结构成员

  •  1
  • jtlz2  · 技术社区  · 8 年前

    我试图使用ctypes来提取由C库初始化的结构(例如,请参见: https://tentacles666.wordpress.com/2012/01/21/python-ctypes-dereferencing-a-pointer-to-a-c )。

    “原型”是:

    mytype * createMyType();
    

    C中的结构为:

    typedef struct
    {
            int              a;
            void             *b;
    }mytype;
    

    在python(3)中!我创建了一个ctypes结构,因此:

    class mytype(ctypes.Structure):
        _fields_ = [("a", ctypes.c_int),
                   ("b", ctypes.POINTER(None))]
    

    C调用是:

    mytype*myinstance = createMyType()
    

    Python调用如下:

    import ctypes
    f=mylib.createMyType
    f.argtypes=()
    f.restype=(ctypes.POINTER(mytype),)
    x=f()
    

    问题是 x 似乎是一个整数;如何将其解释为指针,或根据需要提取 x个 他们自己

    如何访问和修改 x.a x.b ?

    [另请参见 Accessing data from a structure returned by C function in Python using ctypes ,但没有任何结果]

    1 回复  |  直到 7 年前
        1
  •  1
  •   Mark Tolonen    7 年前

    主要是你需要 c_void_p 对于void*,必须用 .contents

    下面是一个工作示例(Windows)。。。

    编辑 :我添加了一个强制转换void指针成员的示例。

    测验h类

    #ifdef EXPORT
    #define API __declspec(dllexport)
    #else
    #define API __declspec(dllimport)
    #endif
    
    typedef struct
    {
            int a;
            void* b;
    } mytype;
    
    API mytype* createMyType();
    API void destroyMyType(mytype* p);
    

    测验c

    #define EXPORT
    #include <stdlib.h>
    #include <stdio.h>
    #include "test.h"
    
    API mytype* createMyType()
    {
        int* tmp;
        mytype* p = malloc(sizeof(mytype));
        p->a = 5;
        tmp = malloc(sizeof(int));
        *tmp = 123;
        p->b = tmp;
        printf("%d %p\n",p->a,p->b);
        return p;
    }
    
    API void destroyMyType(mytype* p)
    {
        free(p->b);
        free(p);
    }
    

    测验py公司

    from ctypes import *
    
    class mytype(Structure):
        _fields_ = [('a',c_int),
                    ('b',c_void_p)]
    
    test = CDLL('test')
    createMyType = test.createMyType
    createMyType.argtypes = None
    createMyType.restype = POINTER(mytype)
    destroyMyType = test.destroyMyType
    destroyMyType.argtypes = POINTER(mytype),
    destroyMyType.restype = None
    
    t = createMyType()
    print('t is',t)
    print('t.a is',t.contents.a)
    print('t.b is',hex(t.contents.b))
    b = cast(t.contents.b,POINTER(c_int))
    print('*b is',b.contents)
    destroyMyType(t)
    

    输出 :请注意,C代码中输出的void*b地址与 t.contents.b 。这个 cast 将该整数转换为 POINTER(c_int) 可以提取内容的地方。

    5 00000216C0E2A5D0
    t is <__main__.LP_mytype object at 0x00000216C30C4A48>
    t.a is 5
    t.b is 0x216c0e2a5d0
    *b is c_long(123)