Python类型cdll.LoadLibrary,实例化一个对象,执行其方法,私有变量地址被截断

2024-09-29 21:38:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我用c编写了一个dll库,用vs2017 64位编译,并尝试用python3.6 64位加载它。但是,对象的成员变量的地址被截断为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脚本:

^{pr2}$

这是地址中成员的地址_调试.txt公司名称:

member_var init address:    0000025259E123C4
member_var process address: 0000000059E123C4

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

OSError: exception: access violation reading 0000000059E123C4

我试图理解这个问题:

  • 将成员_var定义为public而不是private,而不是help,地址仍然被截断。在
  • 将member_var定义为全局变量,则地址正常。所以我猜成员的地址截短要么在将对象返回python时发生,要么在将对象传递回dll时发生。在

Tags: 对象addressvar地址pin成员myfiledetector
1条回答
网友
1楼 · 发布于 2024-09-29 21:38:38

始终(正确)为C中定义的函数指定argtypesrestype,否则(C89样式)将默认为int(通常32bit),生成!!!未定义的行为!!!。在64位上,地址(大于2 GiB)将被截断(这正是您所经历的)。
同一错误的另一个后果是:[SO]: python ctypes issue on different OSes (@CristiFati's answer)。在

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

下面是代码的改编版本。在

探测器.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

代码.py

^{pr2}$

注意事项

  • 正如我在开头所说的,问题是没有指定argtypesrestype(例如,对于DetectorNew:commentdetector_new_func.restype = c_void_p,您将再次遇到问题)
  • 问题中的代码缺少部分(\includes,imports,…),也存在一些语法错误,因此无法编译,因此不遵循[SO]: How to create a Minimal, Complete, and Verifiable example (mcve)准则。请确保在询问时有mcve
  • 您分配的对象(new Detector())也必须被释放(否则,它将生成一个内存泄漏),因此我添加了一个函数(DetectorDelete),它是从(PythonDetector的析构函数调用的
  • 其他(非关键)更改(标识符重命名、一些重构、打印到stdout,…)

输出

(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

相关问题 更多 >

    热门问题