簡體   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