在 Python 中调用 C 语言(1) (测试可用)
https://docs.python.org/zh-cn/3.14/extending/extending.html
https://docs.python.org/zh-cn/3.14/c-api/
在 Python 中调用 C 语言代码是常见的需求,尤其在需要高性能计算、访问底层系统功能或复用已有 C 代码时。Python 提供了多种方式来实现与 C 语言的交互,主要包括以下几种主流方法:
📌 总结对比
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
ctypes |
简单,无需编译 | 类型声明繁琐 | 调用已有 C 动态库 |
| C 扩展(已测试) | 性能最佳,完全控制 | 学习成本高 | 高性能模块开发 |
| Cython | 易于编写,性能好 | 需要编译 | 渐进式优化 Python |
subprocess |
简单易用 | 性能差 | 调用外部程序 |
✅ 1. 使用 ctypes 模块(无需编译 Python 扩展)
适用场景:
- 快速调用已有的 C 动态库(如
.dll、.so、.dylib) - 无需编写额外的 Python 扩展模块
步骤:
1. 编写 C 函数并编译为共享库
// example.c #include <stdio.h> int add(int a, int b) { return a + b; }
编译为共享库(Linux/macOS): bash
gcc -shared -fPIC -o libexample.so example.c
(Windows): bash
gcc -shared -o example.dll example.c
2. 在 Python 中调用
import ctypes # 加载共享库(注意路径和后缀) lib = ctypes.CDLL('./libexample.so') # Windows: './example.dll' # 声明参数和返回值类型 lib.add.argtypes = [ctypes.c_int, ctypes.c_int] lib.add.restype = ctypes.c_int # 调用 C 函数 result = lib.add(3, 4) print(result) # 输出 7
优点:
- 简单易用,无需编译 Python 扩展
- 适合调用已有 C 动态库
缺点:
- 类型声明繁琐
- 性能略低于 C 扩展
- 不支持复杂结构体或回调函数
✅ 2. 编写 C 扩展模块(Python C API)
适用场景:
- 需要高性能的 C 代码嵌入 Python
- 构建可导入的 Python 模块
步骤:
1. 编写 C 扩展代码
// examplemodule.c #include <Python.h> static PyObject* example_add(PyObject* self, PyObject* args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } return Py_BuildValue("i", a + b); } static PyMethodDef ExampleMethods[] = { {"add", example_add, METH_VARARGS, "Add two integers"}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef examplemodule = { PyModuleDef_HEAD_INIT, "example", NULL, -1, ExampleMethods }; PyMODINIT_FUNC PyInit_example(void) { return PyModule_Create(&examplemodule); }
2. 编写 setup.py 编译模块
# setup.py from setuptools import setup, Extension module = Extension('example', sources=['examplemodule.c']) setup( name='example', version='1.0', description='Example C Extension', ext_modules=[module] )
3. 安装并使用模块
//win终端安装
pip show setuptools
pip install setuptools
python setup.py build_ext --inplace
python
import example print(example.add(3, 4)) # 输出 7
编译和执行需在同一个打开的终端
>>> %Run setup.py build_ext --inplace running build_ext copying build\lib.win-amd64-cpython-314\example.cp314-win_amd64.pyd -> >>> import example >>> print(example.add(3, 4)) # 输出 7 7 >>> >>> print(example.hello_world()) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: module 'example' has no attribute 'hello_world' >>>
优点:
- 性能最佳
- 可以完全控制 C 与 Python 的交互
- 可以与 Python 对象交互(如列表、字典)
缺点:
- 编写复杂,需要熟悉 Python C API
- 容易出错(如引用计数、类型检查)
- //-TODO 需要编译
✅ 3. 使用 Cython(Python 与 C 的混合编程)
适用场景:
- 需要将 Python 代码编译为 C 代码以提升性能
- 渐进式优化 Python 代码
步骤:
1. 编写 .pyx 文件
# example.pyx def add(int a, int b): return a + b
2. 编写 setup.py 编译为 C 扩展
# setup.py from setuptools import setup from Cython.Build import cythonize setup( ext_modules=cythonize("example.pyx") )
3. 编译并使用
python setup.py build_ext --inplace
import example print(example.add(3, 4)) # 输出 7
优点:
- 语法接近 Python,学习曲线低
- 支持类型注解,可生成高性能 C 代码
- 可以直接调用 C 函数和结构体
缺点:
- 仍需编译过程
- 对复杂 C 接口支持不如纯 C 扩展
✅ 4. 使用 subprocess 调用外部 C 程序(非函数级)
适用场景:
- 调用独立的 C 程序(如命令行工具)
- 无需函数级集成
import subprocess result = subprocess.run(['./my_c_program', '3', '4'], capture_output=True, text=True) print(result.stdout)
优点:
- 简单,适合脚本调用
缺点:
- 性能差
- 无法直接传递复杂数据结构
- 不适合频繁调用
🚨 常见问题与注意事项
- 类型声明不匹配:如
ctypes中未正确设置argtypes和restype,可能导致崩溃。 - 引用计数管理:在 C 扩展中,忘记
Py_INCREF或Py_DECREF可能导致内存泄漏或崩溃。 - 编译环境依赖:C 扩展和 Cython 需要安装 C 编译器(如 GCC 或 MSVC)。
- 跨平台兼容性:不同系统下共享库的后缀不同(
.so/.dll/.dylib),需注意路径问题。
✅ 推荐选择
- 快速调用已有 C 库 → 使用
ctypes - 高性能 C 扩展模块 → 使用 Python C API
- 渐进式性能优化 → 使用 Cython
- 调用外部 C 程序 → 使用
subprocess
根据你的具体需求选择合适的方法即可。
setuptools
setuptools
Python和C语言混合编程可以通过以下方式实现:
目录
1、实现方式
使用Python的C扩展:Python提供了C扩展的功能,允许我们在Python中调用C语言代码。我们可以编写C语言扩展模块,并将其编译为共享库或动态链接库,然后在Python程序中导入并使用。这种方式需要我们熟悉C语言和Python的C API,并且需要手动编写和维护C扩展代码。
使用Cython:Cython是Python的一个扩展,它可以将Python代码转换为C代码,并编译成可执行文件。使用Cython,我们可以将Python代码中的某些部分替换为C语言代码,从而提高程序的执行效率。Cython的使用相对简单,只需要在Python代码中添加一些注释即可。
使用ctypes库:ctypes是Python的标准库之一,它提供了调用C语言共享库或动态链接库的功能。我们可以编写C语言共享库或动态链接库,并在Python程序中使用ctypes库来调用其中的函数。这种方式不需要我们熟悉C语言和Python的C API,但是需要手动编写和维护C语言代码。
使用SWIG工具:SWIG是一个开源的工具,它可以将C语言代码转换为Python扩展模块。使用SWIG,我们可以将C语言代码封装为Python可调用的函数或类。SWIG的使用需要一定的学习和工作量,但是它可以自动生成Python扩展代码,减少了手动编写和维护的工作量。
2、通过setuptools编译.c文件的实现
当使用Python和C混合编程时,可以通过使用setuptools模块来编译C语言扩展。下面是一个具体的示例,演示如何使用setuptools编译.c文件:
创建一个名为example.c的C语言源文件,其中包含要编译的C代码。例如:
#include <Python.h> static PyObject* hello_world(PyObject* self) { return PyUnicode_FromFormat("Hello, World!"); } static PyMethodDef ExampleMethods[] = { {"hello_world", hello_world, METH_NOARGS, "Print 'Hello, World!'"}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef examplemodule = { PyModuleDef_HEAD_INIT, "example", NULL, -1, ExampleMethods }; PyMODINIT_FUNC PyInit_example(void) { return PyModule_Create(&examplemodule); }
创建一个名为setup.py的Python脚本,用于编译C语言扩展。例如:
from setuptools import setup, Extension module = Extension('example', sources=['example.c']) setup(name='Example', version='1.0', description='This is a demo package', ext_modules=[module])
from setuptools import setup, Extension import os # 将C编译器路径添加到系统环境变量中 os.environ["CC"] = "gcc" # 定义C语言扩展模块 module = Extension('example', sources=['example.c']) # 设置编译选项 setup(name='Example', version='1.0', description='This is a demo package', ext_modules=[module], include_dirs=[os.path.join(os.getcwd(), 'include')], # 添加头文件目录 )
python
在这个示例中,我们将要编译的.c文件命名为example.c,并将它列在sources列表中。
在终端中运行以下命令来编译C语言扩展:
python setup.py build_ext --inplace
这个命令将会编译example.c文件,并生成一个名为example的Python模块。如果编译成功,您可以在Python程序中导入并使用这个模块。例如:
import example print(example.hello_world()) # 输出 "Hello, World!"
python
请确保在运行setup.py之前已经安装了setuptools模块,并且您的系统中已经安装了C编译器。如果使用的是Linux操作系统,可以使用以下命令安装gcc编译器:
sudo apt-get install build-essential
https://gitee.com/powes/,作者:前沿风暴,转载请注明原文链接:https://www.cnblogs.com/Kreos/p/19386029


浙公网安备 33010602011771号