在Python中使用ctypes从DLL访问C typedef结构

u3r8eeie  于 2023-08-03  发布在  Python
关注(0)|答案(1)|浏览(107)

我有一些用C写的函数,我想在Python中运行,并且在尝试访问typedef结构时遇到了一些意想不到的结果。这里是一个最小的可重复的例子。最后,我的问题是如何访问存储在python代码中的共享库中的全局c结构,或者在头文件中定义的typedef,以便在python中重新创建相同的结构。也许我用来编译SO文件的方法没有创建全局变量?:
temp.c文件:

#include "temp.h"
 

aStruct_t aStruct = {0};

extern void AdderFunction(aStruct_t *struct1, int num)
{
    struct1->y = struct1->x;
    struct1->x += num;
}

字符串
temp.h文件

#ifndef _TEMP_H_

#define _TEMP_H_
    
#include <stdint.h>
    
typedef struct aStruct_t
{
        uint32_t x;
        uint32_t y;
        uint32_t z;

} aStruct_t;

extern void AdderFunction(aStruct_t *struct1, int num);

#endif


我把它编译成一个so文件:

gcc -shared -o temp.so -fPIC temp.c


我希望能够访问Python中的C结构aStruct
例如,在

import ctypes
so_file = "../temp.so"
tempLib = ctypes.CDLL(so_file)
tempLib.aStruct.y


但得到错误AttributeError: '_FuncPtr' object has no attribute 'y'
我很惊讶typedef结构是函数指针类型?这是为什么?
我可以通过在python中创建一个类似的结构来解决这个问题,但是这是不可取的,因为我在C代码中有几个相当大的typedef结构,每次我更新结构时,我也必须更新我的python代码。

import ctypes
so_file = "../temp.so"
tempLib = ctypes.CDLL(so_file)
# tempLib.aStruct.y

class aStruct_python(ctypes.Structure):
    _fields_ = [("x1",ctypes.c_uint),
                ("y1",ctypes.c_uint),
                ("z1",ctypes.c_uint)]

tempLib.AdderFunction(ctypes.pointer(struct_py),2)

v1uwarro

v1uwarro1#

你不能不声明结构。DLL中只有导出的C函数和全局变量的名称可用。
使用<type>.in_dll()访问DLL中的全局变量。dll的属性只能是导出函数的名称。
下面是一个完整的例子:

test.c

#ifdef _WIN32
#   define API __declspec(dllexport)  // required to export names from MSVC
#else
#   define API
#endif

#include <stdint.h>

typedef struct aStruct_t {
    uint32_t x;
    uint32_t y;
    uint32_t z;
} aStruct_t;

API aStruct_t aStruct = {0};

API void AdderFunction(aStruct_t *struct1, int num) {
    struct1->y = struct1->x;
    struct1->x += num;
}

字符串

test.py

import ctypes as ct

# Must define the structure.
class aStruct(ct.Structure):

    _fields_ = (("x", ct.c_uint32),
                ("y", ct.c_uint32),
                ("z", ct.c_uint32))

    # Define how the structure prints itself
    def __repr__(self):
        return f'aStruct(x={self.x}, y={self.y}, z={self.z})'

dll = ct.CDLL('./test')
# Recommended: always fully define arguments and return type.
dll.AdderFunction.argtypes = ct.POINTER(aStruct), ct.c_int
dll.AdderFunction.restype = None

# To access a global variable, call in_dll() on its type,
# passing the DLL instance and the exported global variable name.
a = aStruct.in_dll(dll, 'aStruct')
print(a)

# Declare a local instance of the structure to pass to the function.
s = aStruct(1,2,3)
print(s)

# Call function and print updated structure
dll.AdderFunction(ct.byref(s), 2)
print(s)


输出量:

aStruct(x=0, y=0, z=0)
aStruct(x=1, y=2, z=3)
aStruct(x=3, y=1, z=3)

相关问题