【修改版本】Python调用C函数,cffi (附具体例子)
来源:互联网 发布:胡歌幽默知乎 编辑:程序博客网 时间:2024/05/21 21:40
“C Foreign Function Interface for Python”(cffi)
假设存在一个C语言函数,定义在foo.c
文件中,这个函数调用了GSL(GNU Scientific Library)里面的Bessel函数。
// foo.c#include <gsl/gsl_sf_bessel.h>double foo(double a, double b){ return gsl_sf_bessel_J0(a + b);}
如果python要用cffi模块调用函数foo
。首先,我们要使用cffi中的cdef函数定义输入和输出的数据类型 (类比头文件)。
# demo_1.pyfrom cffi import FFIffi = FFI()ffi.cdef("double foo(double, double);")
下一步,我们要使用cffi中的verify函数,把foo
在C语言中的具体实现传给python。
有两种方式可以实现:
1. 把源文件 foo.c
直接传递python
2. 把foo.c
编译成shared library,然后再传递给python
针对第一种方式:
# demo_1.py (cont.)import osfile_dir = os.path.abspath('.')lib = ffi.verify("#include <foo.c>", include_dirs=[file_dir], libraries=['gsl', 'gslcblas'])
verify
函数有三个参数,分别是C语言源文件名,路径,库文件;
foo.c
包含函数foo
定义的C语言源文件;include_dirs
是
foo.c
所在的位置,因为demo_1.py
文件和foo.c
放在了同一个文件家里,所以可以用os.path.abspath('.')
来提取foo.c
的文件夹地址;参数libraries
是需要用到的库文件,gsl库文件和gslclbas文件。因为函数foo
调用了GSL库里面的Bessel函数。 接下来,可以在python中直接调用C语言定义的函数foo
了:
# demo_1.py (cont.)a, b = 1.2, 3.4print lib.foo(a, b)
针对第二种方式:
通过shared library来传递函数foo
的定义,这么做的好处是把foo
和其他用到的库文件比如GSL“打包”成一个新的库文件,比如叫libfoo.so
,之后就可以在python中直接使用libfoo.so
而无需再指定其他库文件了。具体方法如下:
gcc foo.c -shared -lgsl -lgslcblas -o libfoo.so
注意在这一步中我们把gsl和gslclbas这两个库文件“打包”进了libfoo.so
,然后我们就可以在python中通过cffi来调用libfoo.so
了。
# demo_2.pyfrom cffi import FFIffi = FFI()ffi.cdef("double foo(double, double);")import osfile_dir = os.path.abspath('.')lib = ffi.verify("#include <foo.c>", include_dirs=[dir], library_dirs=[dir], libraries=['foo'])a, b = 1.2, 3.4print lib.foo(a, b)
注意观察verify
中的两点使用变化:
1. 多了一个参数library_dirs
用来说明库文件foo
的位置,这是因为libfoo.so
经常不在系统默认的PATH
上(而gsl
等库文件确实一般安装在PATH
上,而且我们也需要用libraray_dirs
这个参数来指明)。
2. 参数libraries
的值变成了[foo]
,而不是['gsl', 'gslcblas']
。这是因为我们已经把gsl
和gslcblas
里的必要信息打包进了libfoo.so
里面。
最后,假如函数foo
的定义非常复杂,我们不想把它直接传给python,那么就可以定义一个头文件foo.h
来包含foo
的函数声名,
// foo.h#ifndef foo_h__#define foo_h__double foo(double, double);#endif
然后把该头文件传递过去就可以了,即
ffi.verify("#include <foo.h>", include_dirs=[dir], library_dirs=[dir], libraries=['foo'])
假设有两个文件: vect3.h 和 vect3.c.
vect3.h如下:
#define HELLO 3typedef struct{ double x; double y; double z; char* label;}Vec3;Vec3* getVec3(double x, double y, double z, char* label);void printVec3(Vec3* v);void addScalar(Vec3* v, double s);void subScalar(Vec3* v, double s);void mulScalar(Vec3* v, double s);void divScalar(Vec3* v, double s);void extendVec3(Vec3* v, char c, double s);void deleteVec3(Vec3* v);
vect3.c定义为:
#include <stdio.h>#include <malloc.h>#include "vect3.h"Vec3* getVec3(double x, double y, double z, char* label){ Vec3* v = (Vec3*)malloc(sizeof(Vec3)); v->x = x; v->y = y; v->z = z; v->label = label; return v;}void deleteVec3(Vec3* v){ if (v==NULL) return; free(v); v = NULL;}void printVec3(Vec3* v){ if(v==NULL)return; printf("x = %.4f, y = %.4f, z = %.4f, label=%s\n", v->x,v->y,v->z,v->label);}void addScalar(Vec3* v, double s){ if (v==NULL) return; v->x += s; v->y += s; v->z += s;}void subScalar(Vec3* v, double s){ if(v==NULL) return; addScalar(v, -s);}void mulScalar(Vec3* v, double s){ if(v==NULL) return; v->x *= s; v->y *= s; v->z *= s;}void divScalar(Vec3* v, double s){ if (v==NULL||!s) return; v->x /= s; v->y /= s; v->z /= s;}void extendVec3(Vec3* v, char c, double s){ if (v == NULL ) return; switch (c){ case '+': addScalar(v, s); break; case '-': subScalar(v ,s); break; case '*': mulScalar(v, s); break; case '/': divScalar(v, s); break; }}int main(int argc, char const *argv[]){ double x, y, z; x = 1.0; y = 2.0; z = 3.0; char* label = "ssdf"; Vec3* v = getVec3(x,y,z,label); printVec3(v); addScalar(v, 3.7); printVec3(v); deleteVec3(v); return 0;}
我们对这个文件进行编译,编译为libvect3.so。这样我们在cffi中就能调用这个动态链接库。
现在我们引入cffi中的FFI类。
from cffi import FFIffi = FFI()
此时我们要先定义好这个动态链接库都有什么函数什么常量可以调用。
即,在cffi中使用ffi.cdef这个函数。
ffi.cdef("""#define HELLO 3typedef struct{ double x; double y; double z; char* label;}Vec3;Vec3* getVec3(double x, double y, double z, char* label);void printVec3(Vec3* v);void addScalar(Vec3* v, double s);void subScalar(Vec3* v, double s);void mulScalar(Vec3* v, double s);void divScalar(Vec3* v, double s);void extendVec3(Vec3* v, char c, double s);void deleteVec3(Vec3* v);""")
这其实就是我们的头文件。
现在可以加载我们的动态链接库。
lib = ffi.dlopen('./libvect3.so')
这时,我们就可以调用C函数了。
原文地址:http://blog.csdn.net/win_in_action/article/details/46564963
http://www.debugrun.com/a/fjyxcbl.html
- 【修改版本】Python调用C函数,cffi (附具体例子)
- Python使用CFFI调用C动态库
- Python使用CFFI调用C动态库
- cffi: 连接python与C的桥梁
- python 如何安装cffi
- Python 调用 C函数
- python 调用 c 函数
- C,C++中输出具体哪个函数被调用了。
- c 函数作形参 的例子, C#调用
- PHP调用C函数简单例子
- Python调用c/c++函数
- Python调用C语言函数
- Python调用C语言函数
- Python调用C语言函数
- Python调用C语言函数
- Python调用C/C++函数
- C调用Python的函数
- Python调用C语言函数
- 常用布局效果07-文本信息展示布局
- C语言如何编译动态库与静态库
- Linux下使用inotify实现文件监控
- 51nod 1642 区间欧拉函数
- 欢迎使用CSDN-markdown编辑器
- 【修改版本】Python调用C函数,cffi (附具体例子)
- JavaScript定义类或对象
- C++知识点
- 集成学习(Ensemble)
- CCF 中间数
- Killing the time
- 关于c++中set集合的使用
- 04.去,过你想要的人生——家:独立生活,家务活要尽早习惯(笔记)
- 第一次使用markdown编辑器_交换两个数组