从python调用c++函数
Posted
技术标签:
【中文标题】从python调用c++函数【英文标题】:call c++ function from python 【发布时间】:2018-05-06 06:40:43 【问题描述】:我遇到一个问题,这个dll java或者php可以调用成功,但是当我使用python调用时出现访问冲突错误,
我想知道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 ,它也无法连接。
很高兴我的同学用她的电脑(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 与 java
虽然我知道应该是环境原因,但我很想知道到底是什么原因造成的?
蟒蛇
每次运行手柄都是不规则号,我同学的电脑是固定号
如:288584672,199521248,1777824736,-607161376(我没有设置restype)
this is using python call dll,cann't connect port 4000
java
也可以得到没有负数的常规数
如:9462886128,9454193200,9458325520,9451683632
this's java call dll
所以我认为应该是这个代码导致错误,但在其他电脑上没有问题,这很神奇
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;
【问题讨论】:
Java 正在返回 64 位值(注意返回数字有多大)。在 python 中,如果您不指定 restype,则默认为int
,这是一个有符号整数,这就是您看到负数的原因。在python中你必须使用c_void_p
,正如我已经解释过的,你还应该修复DLL的代码
据我所知,在 Python ctypes u_int64
类型中不存在。正如我已经解释过的,即使 C 函数原型是整数,你也应该使用 c_void_p
你同学的代码是错误的,她只是幸运的是指针适合32位整数
想你,我会尽快修改的
【参考方案1】:
如果有 C++ 的源代码可能会有所帮助,但我可以猜测一下
我不认为这是相关的,但是:
getcount.retype
缺少 s
,它应该是 restype
。
而且我总是将argtype
定义为一个数组而不是一个元组,如果只有一个参数,我仍然使用一个元素的数组。
如果char*
是一个以空结尾的字符串,您确实需要使用c_char_p
。在这种情况下,强烈建议将const
添加到m_ip
参数中。
如果char*
是指向原始缓冲区的指针(由调用函数填充或未填充),此处不是这种情况,则需要使用POINTER(c_char)
而不是c_char_p
根据错误消息,您的 handle
是一个指针,您应该在 C++ 代码中使用正确的类型:void*
。在你的python中你应该使用c_void_p
它是 64 位代码吗?使用什么工具链/编译器来构建 DLL?这个工具链中 unsigned long 的大小是多少?
编辑:这是您问题的原因:Is Python's ctypes.c_long 64 bit on 64 bit systems?
handle
是您的 DLL 中的一个指针,并且肯定是使用编译器构建的,其中 long
是 64 位,但对于 Windows 上的 64 位 python,long
是 32 位,它无法存储您的指针。你真的应该使用void*
首先你可以尝试在你的python中使用c_void_p
作为句柄而不修改你的源代码,它可能会根据使用的编译器工作。但是由于long
类型的大小没有被任何标准定义,并且可能无法存储指针,所以你真的应该在你的C++代码中使用void*
或uintptr_t
Edit2:如果您使用的是 Visual Studio,而不是 GCC,那么 long 的大小只有 32 位 (Size of long vs int on x64 platform) 所以你必须修复DLL的代码
【讨论】:
谢谢,你觉得win7和win10有区别吗?我想不出更多的区别 不,问题不存在。首先,您的 C++ 代码是错误的,必须按照已经解释的方式进行修复:指针永远不应放入无符号长整数中,具体取决于编译器和平台,它可能不适合整数。请说明 DLL 是如何构建的,使用哪个工具链/编译器以及哪个版本。 DLL使用vs 2010 build ,x64 , release,明天我会修复DLL的代码,现在是1:40,我要睡觉了。 你应该再看一遍我的消息,我不知道你用的是visual studio。问题也出在您的 DLL 源代码中,因为使用 Visual Studio,long 无法在 64 位构建上存储指针 谢谢,我会告诉c++ code wirter,我不懂c++以上是关于从python调用c++函数的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 QT/python 从 Javascript 调用 C++ 函数?