python - 当 C 函数返回动态数组时,Python ctypes 行为异常
问题描述
我正在为 Matlab 的动态库开发 Python 包装类,以在 Python 中读取 Matlab MAT 文件,我遇到了一个我无法从 ctypes 接口解释的奇怪行为。
C 函数签名如下所示:
const mwSize *mxGetDimensions(const mxArray *);
在这里,mwSize
是一个重命名的size_t
,并且mxArray*
是一个不透明的指针。该函数返回 Matlab 数组的“形状”。返回的指针指向 size_t 数组,该数组内部存储在 mxArray 对象中,并且不以null 结尾(其大小通过另一个函数获得)。
要从 Python 调用此函数,我将库设置如下:
libmx = ctypes.cdll.LoadLibrary('libmx.dll')
libmx.mxGetDimensions.restype = ctypes.POINTER(ctypes.c_size_t)
libmx.mxGetDimensions.argtypes = [ctypes.c_void_p]
在获得mxArray*
后VAR
,我打电话给:
dims = libmx.mxGetDimensions(VAR)
print(dims[0],dims[1])
VAR
已知是 2-D 并且具有(1, 13)
(使用 C 程序验证)的形状,但我的 Python 代码(55834574849 0)
在 c_ulonglong 中返回...结果在测试 MAT 文件中存储的所有变量中始终是垃圾。
我究竟做错了什么?其他使用 VAR 的库调用似乎工作正常,因此 VAR 指向有效对象。如上所述,在 C 程序中调用的 mxGetDimensions() 按预期工作。
任何输入将不胜感激!谢谢
解决方案
@Neitsa 在 OP 下的评论中解决了我的直接问题,对 libmx.dll 的进一步调查解决了 Python 和 C 版本之间的剩余差异。
由于 Matlab 的 libmx.dll 可以追溯到很长时间,因为它最初是在 32 位时代编写的,所以 DLL 包含其函数的多个版本以实现向后兼容性。事实证明,这const mwSize *mxGetDimensions(const mxArray *);
是该函数的最旧版本,并且关联的 C 头文件 (matrix.h) 具有#define mxGetDimensions mxGetDimensions_800
用其最新版本覆盖该函数的行。显然,Python 的 ctypes 不检查 C 头文件;所以,留给我筛选头文件以确定要使用哪个版本的函数。
最后,POINTER(c_size_t)
当我将代码更改为:
libmx = ctypes.cdll.LoadLibrary('libmx.dll')
libmx.mxGetDimensions_800.restype = ctypes.POINTER(ctypes.c_size_t)
libmx.mxGetDimensions_800.argtypes = [ctypes.c_void_p]
dims = libmx.mxGetDimensions_800(VAR)
所以,你有它:如果你正在包装一个 3rd-party 动态/共享库,请彻底研究相关的头文件。
推荐阅读
- javascript - 验证用户是否没有任何角色
- mysql - 嗨,我正在工作 Node/express.js 项目,Sequelize 作为 ORM 和 MySQL 作为 DB。谁能知道PLZ是如何固定的
- typescript - 是否可以根据特定条件从对象数组中获取类型?
- r - 跨多个数据框更改列的类别
- python - python - 不能从 os.system() 响应中获取 0
- faunadb - 如何在 FaunaDB 查询语言上选择特定字段?
- r - R:投资组合优化-solve.QP/约束不一致,无解
- c++ - i++ 还是 ++i 更适合这个程序?
- react-native - 使用 tcomb 包对 React Native 进行电子邮件验证
- c++ - GCC 编译错误——编译器本身似乎在 RHEL 8 环境中截断 LOG 文件时出错