1. 程式人生 > >python與c++的混合呼叫

python與c++的混合呼叫

最近用c++寫了一個基於Hidden Markov的輸入法,說是輸入法,其實只有兩個功能,一個功能是讀入語料庫,另一個是輸入拼音返回輸出的漢字。寫完了之後,我在想,既然python這麼好用,我又不想重寫一遍輸入法的程式碼,那麼能不能用python呼叫c++現成的東西呢,於是就有了接下來的內容。這篇部落格的題目是混合呼叫,這裡暫時只寫了python呼叫c++的內容,c++呼叫python等遇到了這方面的問題我再補充,內容有不對的地方歡迎大家提出。

python呼叫c++

呼叫c++動態連結庫

c++端

呼叫c++生成的動態連結庫並不能直接使用c++的類,還是需要通過函式的方式將對類的呼叫轉換為c風格的函式介面。如

#define DLL_API __declspec(dllexport)
extern "C" DLL_API int add(int a, int b);
int add(int a, int b)
{
    return a + b;
}

其中__declspec(dllexport)是宣告該函式為匯出函式,簡單地說就是宣告該函式可以被外部檔案呼叫。具體生成dll的方法這裡就不寫了。對於生成的dll可以用Dependency Walker來檢視,下面是我用Dependency Walker檢視生成的dll的結果,可以看到我定義的add函式。
image

python端

python端的程式主要用到了ctypes模組,我這裡用python3.5來舉例子。

from ctypes import *
dll=WinDLL('vstest.dll')
res=dll.add(1,2)
print(res)
>>> 3

可以看到已經成功呼叫了add函式。

複雜資料型別的傳遞

結構體

c++
struct Structure
{
    int a;
    double b;
    char c;
};
extern "C" DLL_API Structure disp(int a, double b, char c);
Structure disp(int a, double b, char c)
{
    Structure res;
    res.a = a;
    res.b = b;
    res.c = c;
    return
res; }
python
class MyStruct(Structure):
  _fields_=[('a',c_int),
            ('b',c_double),
            ('c',c_char)
            ]
dll=WinDLL('vstest.dll')
dll.disp.restype=MyStruct
a=c_int(1)
b=c_double(2)
c=c_char(b'c')//涉及字元的操作,前面都加b表示位元組操作
res=dll.disp(a,b,c)
print(res.a)
print(res.b)
print(res.c)
>>> 1
>>> 2.0
>>> b'c'

陣列與指標

c++

下面這個函式的功能是將一個大小為10的字元陣列反轉,並且存到令一個字元陣列內,傳出字元陣列指標。

extern "C" DLL_API char* reverse_chararray(char input[10]);
char * reverse_chararray(char input[10])
{
    char *p = new char[10];
    for (int i = 0; i < 9; i++)
        p[i] = input[8 - i];
    p[9] = '\0';
    return p;
}
python
dll=WinDLL('vstest.dll')
c_char10=c_char*10
inp=c_char10(b'A',b'l',b'o',b'h',b'a',b' ',b'C',b'p',b'p')
print(inp.value)
dll.reverse_chararray.restype=c_char_p
res=dll.reverse_chararray(inp)
print(res)
>>> b'Aloha Cpp'
>>> b'ppC aholA'

c++呼叫python

用到時再補

輸入法預測結果

呼叫程式碼

from ctypes import *
class Res(Structure):
  _fields_=[('str',c_wchar_p),
            ('score',c_double)
            ]

dll=WinDLL('cnIME.dll')
dll.query.restype=POINTER(Res)
char_p_array=c_char_p*5
query=char_p_array()
query[0]=c_char_p(b'shu')
query[1]=c_char_p(b'ru')
query[2]=c_char_p(b'fa')
corpus=c_char_p(b'corpus.txt')
if dll.load_corpus(corpus):
  res=dll.query(query,3)
  print(res.contents.str)
  print(res.contents.score)

>>> 輸入法
>>> -11.47650278637253

這裡我輸入“輸入法”的拼音,預測的結果為輸入法,後面的那個數字是得到的打分,實際是概率的對數。輸入法如果有誰感興趣可以去Github看。