使用Python的ctypes,我们可以直接调用由C直接编译出来的函数.其实就是调用动态链接库中的函数.为什么我们需要这样做呢,因为有些时候,我们可能需要一个性能上比较讲究的算法,有些时候,我们可以在Python中使用已经有了的现成的被封闭在动态链接库中的函数.下面是如何调用的示例.
首先,我们用一个乘法来表示一个算法功能.下面是C的程序:
}?
如果在Windows下,你可能需要写成下面这个样子:
#include?windows.h?
BOOL?APIENTRYDll
Main(HANDLE?hModule,?DWORD?dwReason,?LPVOID?lpReserved){?
return?TRUE;
__declspec(dllexport)?
然后,自然是把这个C文件编成动态链接库:
Linux下的编译:
gcc?-c?-fPIC?libtest.c
gcc?-shared?libtest.o?-o?libtest.so?
Windows下的编译:
cl?-LD?libtest.c?-libtest.dll?
于是在我们的Python中可以这样使用:
(其中的libtest.so在Windows下改成libtest.dll即可)
from?ctypes?import?*
import?os
libtest?=?cdll.LoadLibrary(os.getcwd()?+?'/libtest.so')
注意:上面的Python脚本中需要把动态链接库放到当前目录中.
if
__name__=="__main__":
'main'
① Python 调用 C (base)
想在python中调用c函数, 如这儿的fact
#include Python.h
int fact(int n)
{
if (n = 1)
return 1;
else
return n * fact(n - 1);
}
PyObject* wrap_fact(PyObject* self, PyObject* args)
int n, result;
if (! PyArg_ParseTuple(args, "i:fact", n))
return NULL;
result = fact(n);
return Py_BuildValue("i", result);
static PyMethodDef exampleMethods[] =
{"fact", wrap_fact, METH_VARARGS, "Caculate N!"},
{NULL, NULL}
};
void initexample()
PyObject* m;
m = Py_InitModule("example", exampleMethods);
把这段代码存为wrapper.c, 编成so库,
然后在有此so库的目录, 进入python, 可以如下使用
import example
在python中调用C++类成员函数, 如下调用TestFact类中的fact函数,
class TestFact{
public:
TestFact(){};
~TestFact(){};
int fact(int n);
int TestFact::fact(int n)
return n * (n - 1);
TestFact t;
return t.fact(n);
extern "C" //不加会导致找不到initexample
把这段代码存为wrapper.cpp, 编成so库,
Boost库是非常强大的库, 其中的python库可以用来封装c++被python调用, 功能比较强大, 不但可以封装函数还能封装类, 类成员.
首先在ubuntu下安装boost.python, apt-get install libboost-python-dev
#include boost/python.hpp
char const* greet()
return "hello, world";
BOOST_PYTHON_MODULE(hello)
using namespace boost::python;
def("greet", greet);
把代码存为hello.cpp, 编译成so库
import hello
hello.greet()
'hello, world'
ctypes allows to call functions in dlls/shared libraries and has extensive facilities to create, access and manipulate simple and complicated C data types in Python - in other words: wrap libraries in pure Python. It is even possible to implement C callback functions in pure Python.
extern "C"
将代码存为wrapper.cpp不用写python接口封装, 直接编译成so库,
进入python, 可以如下使用
import ctypes
pdll = ctypes.CDLL('/home/ubuntu/tmp/example.so')
在函数声明加入前缀,如
__declspec(dllexport) int Fun(int a, int b)
否则在加载该dll时会提示找不到该符号
在windows下可以通过vs自带的dumpbin工具查看可被调用符号
dumpbin /exports test.dll
C函数在调用过程中关于参数传递和压栈由多种规定,作为dll提供给其他程序调用时,必须明确并统一为同一种调用规定,否则会导致栈破坏,编译器负责具体实现调用规定,主要有以下几种调用规定
python下调用C库有多种方式,ctypes是其中一种比较方便的,调用时首先需要加载dll文件,根据C dll的调用规定不同需要使用不同接口,使用ctypes需要 import ctypes 库
对于简单的C函数,例如 int add(int a, int b) , 此时就可以直接调用了,如
对于较复杂的C函数的参数情况,ctypes调用时对入参和出餐做一定处理,这里分情况讨论
以上包含了几种主要的参数传递情况,ctypes也提供了一个较为完整的python类型和C类型的对照,如下:
ctypes:? 可直接调用c语言动态链接库.
使用步骤:
①. 编译好自己的动态连接库
#Step?1:?test.c#include?stdio.h
int?add(int?a,?int?b)
return?a?+?b;
from?ctypes?import?*mylib?=?CDLL("libtest.so")?或者?cdll.LoadLibrary("libtest.so")?add?=?mylib.add
add.argtypes?=?[c_int,?c_int]?#?参数类型,两个int(c_int是ctypes类型,见上表)
add.restype?=?c_int?#?返回值类型,int?(c_int?是ctypes类型,见上表)