如何在Python中访问KMP生成DLL的C嵌套结构体指针
如何用Python ctypes访问Kotlin Native生成的DLL结构体成员?
问题背景
Kotlin Multiplatform/Native生成的Windows DLL对应C头文件片段:
typedef struct { struct { struct { // ... } root; } kotlin; } libnative_ExportedSymbols; extern libnative_ExportedSymbols* libnative_symbols(void);
C语言中访问root结构体的方式:
libnative_ExportedSymbols* lib = libnative_symbols(); lib->kotlin.root. // ...
尝试用Python ctypes访问时多次触发AttributeError,代码如下:
import ctypes libPath = "path/to/libnative.dll" dll = ctypes.CDLL(libPath) pythonInt = dll.libnative_symbols() print(type(pythonInt)) # <class 'int'> print(pythonInt) # A number, e.g. 1190351680 CPointer = ctypes.POINTER(ctypes.c_long) cLong = ctypes.c_long(pythonInt) cAddress = ctypes.addressof(cLong) cPointer = ctypes.cast(cAddress, CPointer) print(type(pythonInt) == type(cPointer.contents.value)) # true print(pythonInt == cPointer.contents.value) # true try: print(cPointer.kotlin.root) except AttributeError: print("AttributeError") # AttributeError try: print(cPointer.contents.kotlin.root) except AttributeError: print("AttributeError") # AttributeError try: print(cPointer.contents.value.kotlin.root) except AttributeError: print("AttributeError") # AttributeError
解决方法
核心问题是没有用ctypes定义对应嵌套结构体的类型,也未指定函数返回类型,导致ctypes默认把返回的指针当成普通整数处理,无法识别结构体成员。
步骤1:定义对应C的嵌套结构体
用ctypes.Structure子类逐层映射C中的嵌套结构,成员名和类型必须和C头文件完全一致:
import ctypes # 定义最内层的root结构体(根据实际C头文件补充成员) class RootStruct(ctypes.Structure): _fields_ = [ # 示例:如果root里有int类型成员,添加如下行 # ("example_int", ctypes.c_int), # 其他成员按实际情况补充 ] # 定义包含root的kotlin结构体 class KotlinStruct(ctypes.Structure): _fields_ = [ ("root", RootStruct) ] # 定义最外层的导出符号结构体 class LibnativeExportedSymbols(ctypes.Structure): _fields_ = [ ("kotlin", KotlinStruct) ]
步骤2:设置函数返回类型
加载DLL后,给libnative_symbols指定返回类型为结构体指针,避免ctypes默认把返回值当成整数:
libPath = "path/to/libnative.dll" dll = ctypes.CDLL(libPath) # 指定函数返回类型为LibnativeExportedSymbols的指针 dll.libnative_symbols.restype = ctypes.POINTER(LibnativeExportedSymbols)
步骤3:正确访问结构体成员
调用函数后,通过指针的.contents属性获取结构体实例,再逐层访问嵌套成员:
# 获取结构体指针 lib_symbols_ptr = dll.libnative_symbols() # 逐层访问到root结构体 root_instance = lib_symbols_ptr.contents.kotlin.root # 访问root的成员(示例) # print(root_instance.example_int)
关键说明
- 必须严格按照C头文件的结构定义
ctypes.Structure子类,成员名、类型、嵌套层级完全对应,否则无法正确解析内存布局。 - 一定要设置函数的
restype:ctypes默认将函数返回值视为c_int,会把结构体指针转成普通整数,自然无法访问结构体成员。 - 结构体指针通过
.contents获取指向的结构体实例,之后即可用.访问嵌套成员,和C语言的->逻辑一致。
内容的提问来源于stack exchange,提问作者Marco Eckstein
相关产品推荐
相关产品推荐

