使用ctypes实现Python调用C函数传递结构体数组的问题
问题分析与解决方案
首先需要先修正C代码中的明显错误:函数sac_dos_brute声明返回int,但实际返回的是结构体指针tab,这会导致类型不匹配。建议将返回值类型改为reference*,或者返回一个表示执行状态的整数(比如0代表成功)。
Python代码中的核心错误
- 结构体数组创建错误:
[reference()]*2会生成两个指向同一个结构体实例的引用,修改其中一个会同步影响另一个,必须创建独立的结构体实例。 - 参数类型声明错误:未匹配C函数的三个参数(
int,reference*,float),还存在argtype的拼写错误(正确应为argtypes)。 - 函数调用参数缺失:C函数需要三个参数,原代码只传递了两个,且
byref(tab)的用法不符合要求。 - 未指定返回值类型:必须通过
restype告诉ctypes如何解析C函数的返回值。
正确的Python调用代码
from ctypes import * # 加载编译好的DLL dll = CDLL('C:/..../workplease.dll') # 定义与C结构体完全匹配的Python结构体类 class reference(Structure): _fields_ = [ ('UID', c_int), ('prix', c_float), ('poids', c_float), ('quantite', c_int), ('nb_commande', c_int), ] # 声明C函数的参数类型与返回值类型 # 注意:如果C函数返回结构体指针,将restype改为POINTER(reference) dll.sac_dos_brute.argtypes = [c_int, POINTER(reference), c_float] dll.sac_dos_brute.restype = c_int # 对应C函数的返回值类型 # 创建独立的结构体实例数组 nb_produit = 2 tab = [reference() for _ in range(nb_produit)] # 填充第一个结构体数据 tab[0].UID = 234 tab[0].prix = 12.0 tab[0].poids = 234.0 tab[0].quantite = 3 tab[0].nb_commande = 1 # 填充第二个结构体数据 tab[1].UID = 237 tab[1].prix = 15.0 tab[1].poids = 256.0 tab[1].quantite = 6 tab[1].nb_commande = 2 # 将Python结构体数组转换为C兼容的指针 tab_ptr = cast(tab, POINTER(reference)) # 调用C函数,传入完整参数 masse = 100.0 # 根据实际业务需求设置mass值 result = dll.sac_dos_brute(nb_produit, tab_ptr, masse) # 输出C函数处理后的结构体数据(C函数可能修改了结构体内容) for item in tab: print(f"UID: {item.UID}, Prix: {item.prix}, Poids: {item.poids}, Quantite: {item.quantite}, Nb Commande: {item.nb_commande}")
额外注意事项
- 如果C代码使用MSVC编译且函数是
__stdcall调用约定,需要将CDLL替换为windll。 - 结构体的字段顺序、类型必须与C代码完全一致,否则会出现内存对齐错误,导致数据读取异常。
- 如果C函数确实需要返回结构体指针,务必同步修改C代码的返回值声明为
reference*,并将Python中的restype设置为POINTER(reference)。
内容的提问来源于stack exchange,提问作者Thibault Naud
相关产品推荐
相关产品推荐

