You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 13:03:22