python中使用ctypes模块可以在python中直接调用C/C++。
首先要将C/C++编译成动态库(.so),之后python中调用即可
特别注意在调用C++函数需要在函数声明时,加入前缀“ extern “C” ”,这是由于C++支持函数重载功能,在编译时会更改函数名。在函数声明时,前缀extern "C"则确保按C的方式编译。
值得注意的是,一定要有函数输入输出类型的声明,int型不用转换,float和double类型需要进行转换,
ctypes中的变量类型与C中对应如下:
ctypes数据类型 C数据类型
c_char char
c_short short
c_int int
c_long long
c_float float
c_double double
c_void_p void
c_uint8 unsigned char
这里如果c/c++的.so动态库的接口形参的类型python不存在则会报段错误!!
例如:
动态库接口为 string Example(string filePath );
python代码:
import ctypes
from ctypes import *
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
libtestso = cdll.LoadLibrary("./ReadFile.so")
libtestso.Example(convert_type(file))
这时解释器会报段错误,经研究分析是类型不匹配导致解释器报段错
如果.so动态库接口改成char* Example(char filePath[] );
python调用
libtestso = cdll.LoadLibrary("./ReadFile.so")
libtestso.Example(convert_type(file))
就不会出现段错误,但是会导致无法获取的返回字符串,因为返回的地址但是python的变量是动态的所以,
变量被赋值地址,打印变量会认为是int类型,无法打印字符串。
这时我们可以在python中先给变量赋值一个足够大的字符类型数组,然后将数组传参的方式传进去
执行完函数之后可以打印数组,就可以看到传出的字符串啦
c/c++接口代码:
int Example(char file[] ,char* Buf,int *len)
{
char ch[] = "hello world";
memcpy(buf, ch, strlen(ch));
*len = strlen(ch);
printf("%s\n",file);
}
python 代码:
import ctypes
from ctypes import *
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
libtestso = cdll.LoadLibrary("./ReadFile.so")
file ="result"
Len = 123
Buf = create_string_buffer(0, Len)
c_bufLen = c_int(Len)
//传入字符串file ,Buf是传出字符串,c_bufLen是传出字符串的长度
libtestso.Example(convert_type(file),Buf,byref(c_bufLen))
print(c_bufLen.value)
print(string_at(Buf))
这时应会打印
result
hello world