Python调用c/c++代码的ctypes库的使用
编译环境是centos7,ctypes的一些基本用法可以随便百度一下都能找到很多资料,但是很少有提到怎么调用c++函数或者类方法的文章,本文主要介绍的内容包括:
1、怎样调用c++的函数和类方法
2、向c函数中传入回调函数的方法
一、python的ctypes调用c++函数和方法
常规的ctypes调用c函数的方法
//ctest.c
#include <stdio.h>
int func(int a, int b)
{
int res = a + b;
printf("%d + %d = %d\n", a, b, res);
return res;
}
c文件编译:gcc ctest.c -shared -fPIC -o libctest.so
注意:不要加 -c
#pycallc.py
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libctest.so")
lib.func(2, 3)
运行python脚本:python3 pycallc.py
结果如下,能正确运行:
python调用cpp函数:
//cpptest.cpp --> libcpptest.cpp
#include <stdio.h>
int func(int a, int b)
{
int res = a + b;
printf("%d + %d = %d\n", a, b, res);
return res;
}
编译指令:g++ cpptest.cpp -shared -fPIC -o libcpptest.so
#pycallcpp.py
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libcpptest.so")
lib.func(2, 3)
执行 python3 pycallcpp.py会报错,显示找不到func函数,原因正是g++编译器将函数的名字加了前后缀,使用nm命令查看,nm libcpptet.so | grep func 可以看到func的函数名变成_Z4funcii,ii正是func函数的两个int参数
改变python代码里的函数名,然后python代码就能正确的调用c++函数了。
#pycallcpp.py
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libcpptest.so")
lib._Z4funcii(2, 3)
如果使用函数的话使用extern “C”,也可以达到效果,就是让g++编译器使用c的函数编译方式,也就是不加前后缀,但是这种方式c++的函数重载功能就没有了,怀着好奇心,继续研究怎么让python调用c++的类方法。
//cpptest.cpp --> libcpptest.so
#include <stdio.h>
class TEST
{
public:
static int func(int a, int b)
{
int res = a + b;
printf("%d + %d = %d\n", a, b, res);
return res;
}
};
//foo()函数在python中不调用
void foo()
{
TEST t;
t.func(1, 2);
}
使用nm命令查看func函数名变成了什么:nm libcpptest.so | grep func
foo()函数的存在是因为其内部初始化了一个类,并调用了func()方法,使得编译出的动态库能生成func的函数名,如果没有此函数,使用nm命令是找不到这个函数的,具体原因我还没弄清楚,期待有大神留言交流,第二个要注意的点是func()函数必须声明为static,因为类的非静态函数的第一个参数是this指针,c++的类无法在python中传递
#pycallcpp.py
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libcpptest.so")
lib._ZN4TEST4funcEii(2, 3)
二、回调函数传递的问题
1、python中写回调函数作为参数传递给c函数
//ctest.c --> libctest.so
#include <stdio.h>
typedef int (*ADD)(int, int);
int func(ADD f, int a, int b)
{
int sum = f(a, b);
printf("sum = %d\n", sum);
return sum;
}
from ctypes import *
ll = cdll.LoadLibrary
lib = ll("./libctest.so")
def callback(a, b):
return a + b;
cfunctype = CFUNCTYPE(c_int, c_int, c_int)
#第一个是函数返回值,后面两个是参数列表
add = cfunctype(callback)
lib.func(add, 5, 6)
2、在c中写回调函数
//ctest.c --> libctest.so
#include <stdio.h>
typedef int (*ADD)(int, int);
int func(ADD f, int a, int b)
{
int sum = f(a, b);
printf("sum = %d\n", sum);
return sum;
}
int add(int a, int b)
{
return a + b;
}
from ctypes import *
ll = cdll.LoadLibrary
lib = ll("./libctest.so")
lib.func(lib.add, 5, 6)