使用ctypes从python中的DLL访问C typedef结构



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

临时文件:

#include "temp.h"

aStruct_t aStruct = {0};

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

临时文件

#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)

不声明结构是无法逃脱的。DLL中只有导出的C函数和全局变量的名称可用。

使用<type>.in_dll()访问DLL中的全局变量。dll的属性应仅为导出函数的名称。

下面是一个完整的例子:

测试.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;
}

测试.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)

最新更新