Python调用C++ DLL单磁盘正常,多磁盘失败原因咨询(C++用Vector指针)
Python调用C++ DLL获取多磁盘信息失败的原因分析
问题场景
通过Python的ctypes调用C开发的FlashSpeedSta.dll时,单个磁盘信息的获取功能正常,但多磁盘信息获取失败。C端采用std::vector指针实现多磁盘逻辑。
Python代码实现
from ctypes import * # U盘信息结构体 class DiskInfo(Structure): _fields_ = [("total_space", c_long), ("free_space", c_long), ("used_space", c_long), ("user_name", c_char*20)] class ManyDiskInfo(Structure): _fields_ = [("disk_array", DiskInfo * 2)] # 创建实例 obj_di = DiskInfo() obj_mdi = ManyDiskInfo() # 加载DLL dll = windll.LoadLibrary("FlashSpeedSta.dll") disk_path = c_char_p(b"G:\\") # 获取单个磁盘信息 dll.GetDiskSpace.argtypes = [c_char_p, POINTER(DiskInfo)] dll.GetDiskSpace.restype = POINTER(DiskInfo) result = dll.GetDiskSpace(disk_path, byref(obj_di)) # 原代码存在笔误:buref → byref print(obj_di, obj_di.total_space, obj_di.used_space, obj_di.user_name) # 获取多个磁盘信息 dll.GetDiskSpaceed.argtypes = [c_char_p, POINTER(ManyDiskInfo)] dll.GetDiskSpaceed.restype = POINTER(ManyDiskInfo) dll.GetDiskSpaced(disk_path, byref(obj_mdi)) # 函数名不匹配:声明GetDiskSpaceed,调用GetDiskSpaced for n in obj_mid_disk.array: # 变量名错误:obj_mid_disk → obj_mdi print(n, n.total_space, n.free_space, n.used_space, n.user_name)
输出结果
<__main__.DiskInfo object at 0x019AFCB0> 2918 2918 0 b'TW2981' <__main__.DiskInfo object at 0x019AFE90> 0 0 71567872 b'@\nD\x04@\nD\x04' <__main__.DiskInfo object at 0x019AFEE0> 0 0 b''
问题原因分析
1. Python代码的低级错误
- 函数名拼写错误:声明的多磁盘函数是
GetDiskSpaceed,实际调用的是GetDiskSpaced,导致调用了错误的接口。 - 变量名错误:遍历多磁盘数据时使用了不存在的
obj_mid_disk,正确变量应为obj_mdi。 - 单个磁盘调用存在笔误:
buref应为ctypes的标准函数byref。
2. C++ std::vector与Python ctypes的核心不兼容问题
C++的std::vector是标准库容器,内部包含指向数据的指针、容量、元素数量等私有成员,内存布局和Python中定义的固定长度数组结构体ManyDiskInfo完全不匹配:
- Python的
ctypes无法解析std::vector的内部结构,直接传递std::vector<DiskInfo>*给Python时,读取到的是容器的内部指针而非实际磁盘数据,导致输出乱码或错误值。 - 你定义的
ManyDiskInfo是固定长度为2的DiskInfo数组,但C++的std::vector是动态扩容的容器,两者内存结构无对应关系,无法直接映射。
可行的解决方案
方案一:C++端改为固定数组+长度的C风格接口
C++端修改接口,传入足够大的DiskInfo数组和最大长度参数,返回实际填充的磁盘数量:
extern "C" __declspec(dllexport) int GetDiskSpaces(const char* path, DiskInfo* out_array, int max_count) { std::vector<DiskInfo> disks = get_disks(path); int real_count = std::min(max_count, (int)disks.size()); memcpy(out_array, disks.data(), real_count * sizeof(DiskInfo)); return real_count; }
Python端对应调用:
max_disk_num = 10 # 定义足够大的数组长度 disk_array = (DiskInfo * max_disk_num)() real_count = dll.GetDiskSpaces(disk_path, disk_array, max_disk_num) for i in range(real_count): print(disk_array[i].total_space, disk_array[i].user_name.decode('utf-8'))
方案二:C++端返回动态数组+释放接口
C++端动态分配数组,返回数组指针和元素数量,同时提供内存释放接口:
extern "C" __declspec(dllexport) DiskInfo* GetDiskSpaces(const char* path, int* out_count) { std::vector<DiskInfo> disks = get_disks(path); *out_count = disks.size(); DiskInfo* arr = new DiskInfo[disks.size()]; memcpy(arr, disks.data(), disks.size() * sizeof(DiskInfo)); return arr; } extern "C" __declspec(dllexport) void FreeDiskArray(DiskInfo* arr) { delete[] arr; }
Python端调用:
count = c_int() disk_ptr = dll.GetDiskSpaces(disk_path, byref(count)) disk_array = cast(disk_ptr, POINTER(DiskInfo * count.value))[0] for i in range(count.value): print(disk_array[i].total_space, disk_array[i].user_name.decode('utf-8')) dll.FreeDiskArray(disk_ptr) # 必须释放内存,避免泄漏
方案三:C++端避免暴露std::vector
直接在C内部处理std::vector,对外只提供C风格的数组接口,完全屏蔽C容器的细节,确保与ctypes的兼容性。
内容的提问来源于stack exchange,提问作者koobro
相关产品推荐
相关产品推荐

