python3可以通过ctypes模块调用C++库,适当地混合使用将融合python和C++的优势,提升程序的性能。
在ubuntu下,python3通过ctypes模块调用C++动态库,其中的关键在于数据的转换,在python3和C++之间通过ctypes模块将它们的数据联系在一起,在 官网资料中,可支持的数据类型如下:
ctypes类型 | c类型 | python类型 |
---|---|---|
c_bool | _Bool | bool |
c_char | char | 单字符字节对象 |
c_wchar | wchar_t | 但字符字符串 |
c_byte | char | 整型 |
c_ubyte | unsigned char | 整型 |
c_short | short | 整型 |
c_ushort | unsigned short | 整型 |
c_int | int | 整型 |
c_uint | unsigned int | 整型 |
c_long | long | 整型 |
c_ulong | unsigned long | 整型 |
c_ulonglong | unsigned __int64或unsigned long long | 整型 |
c_size_t | size_t | 整型 |
c_ssize_t | ssize_t或Py_ssize_t | 整型 |
c_float | float | 浮点数 |
c_doulbe | double | 浮点数 |
c_longdouble | long double | 浮点数 |
c_char_p | char * | 字节串对象或None |
c_wchar_p | wchar_t * | 字节串或None |
c_void_p | void * | int或None |
在上述数据结构中,可以看到只包含了基础的数据类型,如果传递大量的数据,可通过c_type_p传递字符串的方式进行,也可定义一些结构体传递数据。以下将用一个简单例子介绍通过传递json格式的字符串,程序下载链接为:https://gitee.com/jdi-shen/python-c
主要C++程序讲解
char* json_string() {
Json::Value root;
root["msg"] = "msg";
root["x"] = 2.5;
//std::string json_str = root.toStyledString(); //将json格式数据转变成字符串,程序将会出错
std::string json_str = Json::FastWriter().write(root); //将json格式数据转变成字符串
//如果通过const_cast将string转变成char*,python将得到乱码
static std::pair<char*, uint> c("", 0); //first表示字符串数据,second表示字符串的大小
if(c.second != json_str.size()) { //如果与上次字符串数据的长度不同,则释放内存,避免内存泄漏
if(c.second != 0) { //如果字符串的长度为0,则不需要释放内存
delete c.first;
}
c.first = new char(json_str.size()); //此处将发生内存泄漏的情况
c.second = json_str.size();
}
for(int i = 0; i < json_str.size(); i++) { //将string转变成char*
c.first[i] = json_str[i];
}
return c.first;
}
python3程序
# -*- coding: utf-8 -*-
import ctypes
# 指定动态链接库
lib = ctypes.cdll.LoadLibrary('../lib/libcpp_lib.so')
#将python类型转换成c类型,支持int, float,string的变量和数组的转换
def convert_type(input):
ctypes_map = {int:ctypes.c_int,
float:ctypes.c_double,
str:ctypes.c_char_p
}
input_type = type(input)
if input_type is list:
length = len(input)
if length==0:
print("convert type failed...input is "+input)
return null
else:
arr = (ctypes_map[type(input[0])] * length)()
for i in range(length):
arr[i] = bytes(input[i],encoding="utf-8") if (type(input[0]) is str) else input[i]
return arr
else:
if input_type in ctypes_map:
return ctypes_map[input_type](bytes(input,encoding="utf-8") if type(input) is str else input)
else:
print("convert type failed...input is "+input)
return null
import json
import time
if __name__ == '__main__':
#需要指定返回值的类型,默认是int
lib.add.restype = ctypes.c_double
print(lib.add(convert_type(3.0), convert_type(2.0)))
lib.json_string.restype = ctypes.c_char_p
print(lib.json_string())
# 由于数据格式不正确,出现乱码情况
lib.string_test.restype = ctypes.c_char_p
print(lib.string_test())
注意事项
- C++中的函数需要在声明处加入“extern “C” ”;
- jsoncpp的版本非常多,推荐使用gitee上的版本:https://gitee.com/openharmony/third_party_jsoncpp.git;
- python通过上述方式获得字符串后,会在字符串末尾增加一些不预期的字符,需要清除后再进行解析;