最近用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
函数。
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看。