我在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 cdll
lib = 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 = 1024
a = 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: 0000025259E123C4
member_var process address: 0000000059E123C4
因此访问它会触发内存访问错误:
OSError: exception: access violation reading 0000000059E123C4
我试图了解这个问题的一些尝试:
始终(正确)为C中定义的函数指定argtypes和restype,否则(C89样式)它们将默认为int(通常为32位),生成!!!未定义的行为!!!在64位,地址(大于2 GiB)将被截断(这正是您正在经历的)。 同样错误的另一个后果:[SO]: python ctypes issue on different OSes (@CristiFati's answer)。
此外,遇到问题时,不要忘记[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\n", 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.朋友:
import sys
from ctypes import CDLL, POINTER, \
c_int, c_void_p
import numpy as np
sim_dll = CDLL("./sim.dll")
detector_new_func = sim_dll.DetectorNew
detector_new_func.restype = c_void_p
detector_process_func = sim_dll.DetectorProcess
detector_process_func.argtypes = [c_void_p, POINTER(c_int), POINTER(c_int), c_int]
detector_delete_func = sim_dll.DetectorDelete
detector_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}\n".format(sys.version, sys.platform))
main()
笔记:
detector_new_func.restype = c_void_p
,你会再遇到问题)new Detector()
)也必须被释放(否则,它会产生内存泄漏),所以我添加了一个函数(DetectorDelete - 要做到这一点),这是从(Python)Detector的析构函数调用的输出:
(py35x64_tes1) e:\Work\Dev\StackOverflow\q052268294>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64 (py35x64_test) e:\Work\Dev\StackOverflow\q052268294>dir /b code.py detector.cpp (py35x64_test) e:\Work\Dev\StackOverflow\q052268294>cl /nologo /DDLL /EHsc detector.cpp /link /DLL /OUT:sim.dll detector.cpp Creating library sim.lib and object sim.exp (py35x64_test) e:\Work\Dev\StackOverflow\q052268294>dir /b code.py detector.cpp detector.obj sim.dll sim.exp sim.lib (py35x64_test) e:\Work\Dev\StackOverflow\q052268294>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" ./code.py Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32 From C - [detector.cpp] (28) - [Detector::Detector]: &m_var: 0x0000020CE366E270 From C - [detector.cpp] (34) - [Detector::process]: &m_var: 0x0000020CE366E270