当前位置:首页>python>Python与CC++互操作技术选型之(一)cffi

Python与CC++互操作技术选型之(一)cffi

  • 2026-10-11 06:14:43
Python与CC++互操作技术选型之(一)cffi

Tiobe上,Python长期霸榜编程语言第一,但从我的角度来说,Python其实就是个渣渣,它完全是靠给C/C++当做胶水,才能活成现在如此滋润的地步。几十年来,积累下来的C/C++库,一旦套上了Python的皮,就显得眉清目秀了!

那么,到底如何用Python给C/C++当胶水呢?

Python调用C/C++,市面上能用的路子其实就那么几条:

ctypes、cffi、还有pybind11和nanobind这种专门给C++用的绑定库。

ctypes与cffi:站在C这一侧

这里先说说ctypes和cffi的调用方法。

ctypes和cffi都属于FFI(Foreign Function Interface)方案,核心思路是在Python这边加载编译好的动态链接库,然后直接调用里面的函数。它们的视角是站在Python这一侧,向C世界发起调用。

但具体怎么实现这个调用,两者的设计哲学有明显的差异。

ctypes:标准库的朴素方案

ctypes是Python标准库的一部分,优点是不需要安装任何第三方包。

它的做法很直接:用CDLL("./mylib.dll")加载库,然后通过设置argtypes和restype来声明函数的参数和返回值类型。

比如,下面这里有一个dll,要通过ctypes和cffi来调用:

下面是一段代码来演示各种常见操作,传结构体指针,再到把C++对象伪装成不透明指针传来传去,进行dll的调用:

强烈提醒,上面ctypes库的使用要用这种相对路径的方式:CDLL("./mylib.dll"),否则出错。

ctypes的好处是零额外依赖,任何一个Python环境都能用。

代价是每个函数都需要单独声明argtypes和restype,接口多起来之后代码会显得比较啰嗦。而且ctypes本质上是和C的二进制接口(ABI)打交道,如果结构体的内存布局对不上,运行时可能会出一些难以追踪的问题。

cffi:来自LuaJIT的设计

cffi和ctypes最大的不同,在于它的设计直接继承了LuaJIT的FFI。

这是LuaJIT的一个标志性特性,在Lua社区里以“性能好、用起来自然”著称。

cffi的作者Armin Rigo和Maciej Fijalkowski在设计之初就明确提到了这一点:cffi的接口是基于LuaJIT's FFI的,遵循几个核心原则。

cffi的做法是让用户用C语言的语法来声明要调用的接口,然后由cffi来处理剩下的转换工作:

强烈提醒,与前面ctypes库不一样,这里cffi库的使用要用这种方式:ffi.dlopen("mylib.dll"),否则出错。

对比ctypes的写法,cffi把接口声明集中在一段C代码里,直接从头文件复制粘贴过来就能用,不需要像ctypes那样逐个函数设置argtypes。

这背后反映了cffi的设计目标:让用户只懂C和Python,不需要学第三种语言或一套新的API。

对比来看,ctypes的写法更Pythonic,但每个函数都要单独声明argtypes和restype,接口多了之后代码会显得很啰嗦。

cffi把声明集中在一起,读起来更像C头文件,但需要额外安装cffi包。

性能上两者都属于FFI(外部函数接口)方案,调用C函数时都需要做类型转换和数据编组。有测试数据显示ctypes的调用开销在100纳秒到几微秒这个量级,cffi略快一些,但差异在实际项目中通常感知不到。

真正麻烦的是处理C++——这两套方案都是为C设计的,想调用C++的类?得自己在C层写一堆包装函数,把对象变成void*指针传来传去,既丑陋又容易出错。

ctypes适合的场景是:你有一个现成的C库,想快速在Python里用起来,而且不想给项目增加额外依赖。

cffi则是在你需要更安全、更规范的接口声明时的选择,尤其如果你在用PyPy,cffi几乎是官方推荐。

cffi与LuaJIT FFI的关系

cffi和LuaJIT FFI的关系值得多说两句。

LuaJIT的FFI是在Lua社区公认的“杀手级特性”,它让Lua可以直接调用C函数,而且性能非常接近手写的C扩展。

cffi在设计上高度模仿了LuaJIT FFI的API风格——比如ffi.cdef()声明接口、ffi.new()分配C结构体内存、ffi.string()转换C字符串——这些用法在LuaJIT FFI里都能找到对应的影子。

但cffi并不是简单的移植。它在LuaJIT FFI的基础上增加了Python特有的集成——比如和PyPy的深度配合、对Python C API的兼容性处理等。cffi的作者之一Armin Rigo同时也是PyPy的核心开发者,这也解释了为什么cffi对PyPy的支持比ctypes好得多。

所以,对于一个熟悉Luajit的人来说,当然是强烈建议使用cffi了。一套方案,同时适用于lua和python,想想就开心。

最新文章

随机文章