使用Python和ctypes将对象作为参数传递时发生读取冲突

2024-06-11 16:46:36 发布

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

我正在尝试使用C++来公开C++中现有的硬件API到Python。现有的API创建一个通信套接字对象,然后通过引用将该对象传递给使用它与硬件通信的其他组件。在完整的API中有很多无关的细节,所以我将其剥离为一个简单的示例,它展示了我在完整系统中看到的相同失败。我不是一个专业的程序员,而且对Python完全陌生,所以我怀疑我在做一些愚蠢的事情。本机C++代码包括:

通信类

通信h

#ifndef COMMS_H
#define COMMS_H

#include <iostream>

using std::string;
using std::uint32_t;
using std::cout;
using std::endl;

class Comms
{
public:
    Comms();
    void getStatus();

private:
    string   m_addr;
    uint32_t m_port;
};

#endif // COMMS_H

你知道吗通信cpp你知道吗

#include "comms.h"

Comms::Comms()
{
    m_addr = "192.168.2.1";
    m_port = 5000;
}

void Comms::getStatus()
{
    cout << "Comms object handle is " << this << endl;
    cout << "Comms address is " << m_addr << endl;
    cout << "Comms port is " << m_port << endl << endl;
}

// Extern methods for Python binding via ctypes
extern "C" {
    Comms* Comms_new(){ return new Comms(); }
    void Comms_getStatus(Comms* comms){ comms->getStatus(); }
}

一个UserApp类,它采用Comms类型的参数,通过引用传递。你知道吗

用户应用程序.h

#ifndef USERAPP_H
#define USERAPP_H

#include <iostream>
#include "../Comms/comms.h"

using std::cout;
using std::endl;

class UserApp
{
public:
    UserApp(Comms *theComms);
};

#endif // USERAPP_H

你知道吗用户应用程序.cpp你知道吗

#include "userapp.h"

UserApp::UserApp(Comms *theComms)
{    
    cout << "New UserApp created, Comms object passed by reference" << endl;
    cout << "UserApp handle is " << this << endl;
    cout << "Comms handle is " << theComms << endl << endl;
    theComms->getStatus();
}

// Extern methods for Python binding via ctypes
extern "C" {
    UserApp* UserApp_new(Comms *theComms){ return new UserApp(theComms); }
}
在C++中,这一切都很好,我有一个简单的例子主.cpp(在Qt中运行)每个类有一个实例化。。。你知道吗

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Comms myComms;
    myComms.getStatus();

    UserApp myUserApp(&myComms);

    return a.exec();
}

……结果与我预期的一致:

Comms object handle is 0x28fea0
Comms address is 192.168.2.1
Comms port is 5000

New UserApp created, Comms object passed by reference
UserApp handle is 0x28fe9f
Comms handle is 0x28fea0

Comms object handle is 0x28fea0
Comms address is 192.168.2.1
Comms port is 5000

将所有这些绑定到Python,我已经创建了基于上面的DLL,并编写了以下类来反映C++版本:

你知道吗商务部你知道吗

from ctypes import *
import os
commsLib = cdll.LoadLibrary("Comms.dll")

class Comms(object):
    def __init__(self):
        self.obj = commsLib.Comms_new()  

    def getStatus(self):
        commsLib.Comms_getStatus(self.obj)

你知道吗用户应用程序.py你知道吗

from ctypes import *
import os

UserAppLib = cdll.LoadLibrary("UserApp.dll")

class UserApp(object):
    def __init__(self, comms):
        self.obj = UserAppLib.UserApp_new(comms)    

和我的Python顶层如下,再次试图解释我在C++中所做的:

from ctypes import *

from Comms  import Comms
from UserApp import UserApp

myComms = Comms()
myComms.getStatus()

myUserApp = UserApp(py_object(myComms))

Python输出如下。我可以看到myComms的创建看起来不错,但是当我尝试将其传递给myUserApp时,myComms对象引用没有绑定,代码抛出了访问冲突OSError。我做错什么了?你知道吗

Comms object handle is 0x183048
Comms address is 192.168.2.1
Comms port is 5000

New UserApp created, Comms object passed by reference
UserApp handle is 0x183078
Comms handle is 0x568bb0

Comms object handle is 0x568bb0
Traceback (most recent call last):
  File "wrapper_api_UnitTest.py", line 9, in <module>
    myUserApp = UserApp(py_object(myComms))
  File "c:\Temp\ctypes_test\python\UserApp.py", line 8, in __init__
    self.obj = UserAppLib.UserApp_new(comms)    
OSError: exception: access violation reading 0xFFFFFFF6

Tags: importselfnewobjectisportuserappusing