关于ZAKER 融媒体解决方案 合作 加入

Python ctypes cdll.LoadLibrary, 实例化一个对象 , 执 .

CocoaChina 09-19

我在 c 中编写了一个 dll 库 , 使用 vs2017 64 位编译 , 并尝试使用 64 位python3.6 加载它 . 但是 , 对象的成员变量的地址被截断为 32 位 .

这是我的 sim.c 文件 , 它被编译为 sim.dll:

class Detector {public: Detector ( ) ; void process ( int* pin, int* pout, int n ) ;private: int member_var;};Detector::Detector ( ) { memset ( &member_var, 0, sizeof ( member_var ) ) ; myfile.open ( "addr_debug.txt" ) ; myfile << "member_var init address: " << &member_var << endl;}void Detector::process ( int* pin, int* pout, int n ) ;{ myfile << "member_var process address: " << &member_var << endl; myfile.close ( ) ;}#define DllExport __declspec ( dllexport ) extern "C" { DllExport Detector* Detector_new ( ) { return new Detector ( ) ; } DllExport void Detector_process ( Detector* det, int* pin, int* pout, int n ) { det->process ( pin, pout, n ) ; }}

这是我的 python 脚本:

from ctypes import cdlllib = cdll.LoadLibrary ( r'sim.dll' ) class Detector ( object ) : def __init__ ( self ) : self.obj = lib.Detector_new ( ) def process ( self,pin, pout, n ) : lib.Detector_process ( self.obj,pin, pout, n ) detector = Detector ( ) n = 1024a = np.arange ( n, dtype=np.uint32 ) b = np.zeros ( n, dtype=np.int32 ) aptr = a.ctypes.data_as ( ctypes.POINTER ( ctypes.c_int ) ) bptr = b.ctypes.data_as ( ctypes.POINTER ( ctypes.c_int ) ) detector.process ( aptr, bptr, n )

这是 addr_debug.txt 中 member_var 的地址:

member_var init address: 0000025259E123C4member_var process address: 0000000059E123C4

因此访问它会触发内存访问错误:

OSError: exception: access violation reading 0000000059E123C4

我试图了解这个问题的一些尝试:

> 将 member_var 定义为 public 而不是 private, 而不是帮助 , 地址仍然被截断 .

> 将 member_var 定义为全局变量 , 然后地址就可以了 . 所以我猜想在将对象返回到 python 或将对象传递回 dll 时会发生 member_var 地址截断 .

最佳答案

Always ( CORRECTLY ) 为 C 中定义的函数指定 argtypes 和 restype, 否则 ( C89 样式 ) 它们将默认为 int ( 32bit ) , 生成 !!! 未定义的行为 !!! 在 64 位 , 它可能会导致截断 ( 这正是您正在经历的 ) .

此外 , 遇到问题时 , 不要忘记 [ Python 3.Docs ] : ctypes – A foreign function library for Python.

下面是您的代码的改编版本 .

detector.cpp:

#include <stdio.h>#include <memory.h>#include <fstream>#define C_TAG "From C"#define PRINT_MSG_2SP ( ARG0, ARG1 ) printf ( "%s - [ %s ] ( %d ) - [ %s ] : %s: 0x%0p", C_TAG, __FILE__, __LINE__, __FUNCTION__, ARG0, ARG1 ) using std::endl;std::ofstream outFile;class Detector { public: Detector ( ) ; void process ( int *pIn, int *pOut, int n ) ; private: int m_var;};Detector::Detector ( ) : m_var ( 0 ) { outFile.open ( "addr_debug.txt" ) ; outFile << "m_var init address: " << &m_var << endl; PRINT_MSG_2SP ( "&m_var", &m_var ) ;}void Detector::process ( int *pIn, int *pOut, int n ) { outFile << "m_var process address: " << &m_var << endl; outFile.close ( ) ; PRINT_MSG_2SP ( "&m_var", &m_var ) ;}#define SIM_EXPORT __declspec ( dllexport ) #if defined ( __cplusplus ) extern "C" {#endif SIM_EXPORT Detector *DetectorNew ( ) { return new Detector ( ) ; } SIM_EXPORT void DetectorProcess ( Detector *pDet, int *pIn, int *pOut, int n ) { pDet->process ( pIn, pOut, n ) ; } SIM_EXPORT void DetectorDelete ( Detector *pDet ) { delete pDet; }#if defined ( __cplusplus ) }#endif

code.py:

import sysfrom ctypes import CDLL, POINTER, n c_int, c_void_pimport numpy as npsim_dll = CDLL ( "./sim.dll" ) detector_new_func = sim_dll.DetectorNewdetector_new_func.restype = c_void_pdetector_process_func = sim_dll.DetectorProcessdetector_process_func.argtypes = [ c_void_p, POINTER ( c_int ) , POINTER ( c_int ) , c_int ] detector_delete_func = sim_dll.DetectorDeletedetector_delete_func.argtypes = [ c_void_p ] class Detector ( ) : def __init__ ( self ) : self.obj = detector_new_func ( ) def process ( self, pin, pout, n ) : detector_process_func ( self.obj, pin, pout, n ) def __del__ ( self ) : detector_delete_func ( self.obj ) def main ( ) : detector = Detector ( ) n = 1024 a = np.arange ( n, dtype=np.uint32 ) b = np.zeros ( n, dtype=np.int32 ) aptr = a.ctypes.data_as ( POINTER ( c_int ) ) bptr = b.ctypes.data_as ( POINTER ( c_int ) ) detector.process ( aptr, bptr, n ) if __name__ == "__main__": print ( "Python {:s} on {:s}".format ( sys.version, sys.platform ) ) main ( )

笔记:

> 正如我在开头所说 , 问题是 argtypes 和 restype 没有被指定 ( 例如对于 DetectorNew:注释 detector_new_func.restype = c_void_p, 你会再次遇到问题 )

> 问题中的代码缺少部分 ( #includes,imports, … ) , 也存在一些语法错误 , 因此无法编译 , 因此不遵循 [ SO ] : How to create a Minimal, Complete, and Verifiable example ( mcve ) 准则 . 请问时确保有 mcve

> 你分配的对象 ( 新的 Detector ( ) ) 也必须被释放 ( 否则 , 它会产生内存泄漏 ) , 所以我添加了一个函数 ( DetectorDelete – 来做 ) , 从 ( Python ) Detector 的析构函数调用

> 其他 ( 非关键 ) 更改 ( 标识符重命名 , 一点重构 , 打印到 stdout, …… )

输出:

06002

以上内容由"CocoaChina"上传发布 查看原文
相关标签 python对象

觉得文章不错,微信扫描分享好友

扫码分享