繁体   English   中英

从python调用c ++函数

[英]call c++ function from python

我遇到一个问题,这个dll java或者php可以调用成功,但是当我使用python调用get access violation错误时,

我想知道c ++ char *是ctypes c_char_p的错误,我怎么能用python ctypes map c ++ char *

c ++ dll定义

#define Health_API extern "C" __declspec(dllexport)
Health_API unsigned long Initialization(int m_type,char * m_ip,int m_port)
Health_API int GetRecordCount(unsigned long m_handle)

python代码

from ctypes import *

lib = cdll.LoadLibrary(r"./Health.dll")

inita = lib.Initialization
inita.argtype = (c_int, c_char_p, c_int)
inita.restype = c_ulong

getcount = lib.GetRecordCount
getcount.argtype = c_ulong
getcount.retype = c_int
# here call
handle = inita(5, '127.0.0.1'.encode(), 4000)
print(handle)
result = getcount(handle)

错误信息:

2675930080 
Traceback (most recent call last):
  File "C:/Users/JayTam/PycharmProjects/DecoratorDemo/demo.py", line 14, in <module>
    print(getcount(handle))
OSError: exception: access violation reading 0x000000009F7F73E0

修改后

我发现如果没有定义restype = long,它会返回负数,这是一个值得注意的问题,但我更改了restype = u_int64,它也无法连接。

令我高兴的是,我的shcoolmate使用她的电脑(win7 x64)调用相同的dll成功,使用简单的代码如下

from ctypes import *

lib = cdll.LoadLibrary("./Health.dll")
handle = lib.Initialization(5, '127.0.0.1'.encode(), 4000)
lib.GetRecordList(handle, '')

我是win10 x64,我的python环境是annaconda,我和她改变了相同的环境,使用相同的代码,仍然返回相同的错误

python vs java

虽然我知道它应该是环境原因,但我真的想知道究竟是什么导致了它?

蟒蛇

每个运行句柄都是不规则号码,我同学的pc得到常规号码

如:288584672,199521248,1777824736,-607161376(我不设置restype)

这是使用python调用dll,无法连接端口4000

java的

也可以获得没有负数的常规数字

如:9462886128,9454193200,9458325520,9451683632

这是java调用dll

所以我认为应该是这个代码casue错误,但在其他PC没有问题,这是惊人的

handle = lib.Initialization(5, '127.0.0.1'.encode(), 4000)

c ++ dll:

Health_API unsigned long Initialization(int m_type,char* m_ip,int m_port)
{
    CHandleNode* node;
    switch(m_type)
    {
    case BASEINFO:
        {
            CBaseInfo* baseInfo = new CBaseInfo;
            baseInfo->InitModule(m_ip,m_port);
            node = m_info.AddMCUNode((unsigned long)baseInfo);
            node->SetType(m_type);
            return (unsigned long)baseInfo;
        }
        break;
    case BASEINFO_ALLERGENS:
        {
            CBaseInfo_Allergens* baseInfo_Allergens = new CBaseInfo_Allergens;
            baseInfo_Allergens->InitModule(m_ip,m_port);
            node = m_info.AddMCUNode((unsigned long)baseInfo_Allergens);
            node->SetType(m_type);
            return (unsigned long)baseInfo_Allergens;
        }
        break;
    . (case too many, ... represent them)
    .
    .
    }
    return -1;
}


Health_API int GetRecordList(unsigned long m_handle,char* m_index)
{
    CHandleNode* node = m_info.GetMCUNode(m_handle);
    if( node == NULL)
    {
        return -1;
    }
    switch(node->GetType())
    {
    case BASEINFO:
        {
            CBaseInfo* baseInfo = (CBaseInfo*)m_handle;
            return baseInfo->GetRecordList(m_index);
        }
        break;
    case BASEINFO_ALLERGENS:
        {
            CBaseInfo_Allergens* baseInfo_Allergens = (CBaseInfo_Allergens *)m_handle;
            return baseInfo_Allergens->GetRecordList(m_index);
        }
        break;
    . (case too many, ... represent them)
    .
    .
    }
    return -1;
}

拥有C ++的源代码可能会有所帮助,但我可以做一些猜测

我不认为这是相关的,但是:

  • getcount.retype缺少s ,应该是restype
  • 我总是将argtype定义为数组而不是元组,如果只有一个参数,我仍然使用一个元素的数组。

如果char*是以空字符结尾的字符串,则确实需要使用c_char_p 在这种情况下,强烈建议在m_ip参数中添加一个const

如果char*是指向原始缓冲区的指针(由调用函数填充或不填充),这不是这里的情况,则需要使用POINTER(c_char)而不是c_char_p

根据错误消息,您的handle是一个指针,您应该在C ++代码中使用正确的类型: void* 在你的python中你应该使用c_void_p

是64位代码吗? 使用什么工具链/编译器来构建DLL? 这个工具链中unsigned long的大小是多少?

编辑:这里是你的问题的原因: 在64位系统上Python是ctypes.c_long 64位吗?

handle是DLL中的一个指针,当然是使用long为64位的编译器构建的,但对于Windows上的python 64位, long为32位,无法存储指针。 你真的应该使用一个void*

首先,您可以尝试在python中使用c_void_p来处理句柄,而无需修改源代码,它可能会根据所使用的编译器而有效。 但是由于long类型的大小没有被任何标准定义,并且可能无法存储指针,所以你真的应该在你的C ++代码中使用void*uintptr_t

Edit2:如果你使用的是visual studio,而不是GCC,那么long的大小只有32位( x64平台上的长度与int的大小 )所以你必须修复DLL的代码

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM