Python中调用C++代码的方法总结

 更新时间:2025年11月18日 08:34:49   作者:梦_鱼  
这篇文章主要为大家详细介绍了Python中调用C++代码的相关方法,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下

1. extern "C" {} 包裹导出函数

// C++ 中存在名称修饰,通过 extern "C" {} 将C++函数导出为C函数
// 1. 为类的每个函数创建C风格接口,第一个参数为对象指针
// 2. 提供 create(构造) destroy(析构) 函数管理对象的生命周期
#include <string>

// C++类定义
class Calculator {
private:
int base;
public:
Calculator(int b) : base(b) {}
int add(int a) { return base + a; }
std::string greet(const std::string& name) { return "Hello, " + name; }
};

// C风格函数
extern "C" {

// 创建对象(对应构造函数)
Calculator* Calculator_create(int base) {
return new Calculator(base);
}

// 销毁对象(对应析构函数)
void Calculator_destroy(Calculator* obj) {
delete obj;
}

// 封装成员函数
int Calculator_add(Calculator* obj, int a) {
return obj->add(a);
}

// 字符串处理需要特殊转换(C++ string -> char*)
const char* Calculator_greet(Calculator* obj, const char* name) {
static std::string result;  // 注意:静态变量在多线程中不安全
result = obj->greet(std::string(name));
return result.c_str();
}

}

2. 将C++代码编译为动态库

# 使用C++编译器,保留 -f PIC -shared 参数生成位置无关的动态库
g++ -shared -fPIC -o libcalc.so example.cpp

3.python ctypes调用动态库

使用python的ctypes库调用动态库(加载动态库 -> 定义C函数的输入参数与返回参数 -> 调用动态库函数)

  • 用 c_void_p 类型存储C++对象的指针
  • 字符串通过bytes类型转换(encode/decode)
  • 实现 del 方法自动释放C++对象,避免内存泄漏
import ctypes
import os


class CalculatorWrapper:
    """C++ Calculator类的Python封装器"""

    def __init__(self):
        # 加载动态库
        self.lib = self._load_library()
        # 配置C接口函数原型
        self._setup_functions()
        # 存储C++对象指针
        self.obj_ptr = None

    def _load_library(self):
        """根据操作系统加载对应的库文件"""
        try:
            if os.name == "nt":
                return ctypes.CDLL("./calc.dll")
            elif os.name == "posix":
                return ctypes.CDLL("./libcalc.so")
            else:
                raise OSError("不支持的操作系统")
        except OSError as e:
            raise RuntimeError(f"加载库失败: {e}")

    def _setup_functions(self):
        """定义C接口函数的参数类型和返回值类型"""
        # 创建对象
        self.lib.Calculator_create.argtypes = [ctypes.c_int]
        self.lib.Calculator_create.restype = ctypes.c_void_p  # 返回对象指针

        # 销毁对象
        self.lib.Calculator_destroy.argtypes = [ctypes.c_void_p]
        self.lib.Calculator_destroy.restype = None

        # 加法函数
        self.lib.Calculator_add.argtypes = [ctypes.c_void_p, ctypes.c_int]
        self.lib.Calculator_add.restype = ctypes.c_int

        # 字符串问候函数
        self.lib.Calculator_greet.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
        self.lib.Calculator_greet.restype = ctypes.c_char_p

    def create(self, base_value):
        """创建C++ Calculator实例"""
        self.obj_ptr = self.lib.Calculator_create(base_value)
        if not self.obj_ptr:
            raise RuntimeError("创建C++对象失败")

    def add(self, a):
        """调用加法方法"""
        self._check_object()
        return self.lib.Calculator_add(self.obj_ptr, a)

    def greet(self, name):
        """调用问候方法(处理字符串转换)"""
        self._check_object()
        # Python字符串转C字符串(bytes类型)
        c_name = name.encode('utf-8')
        result_ptr = self.lib.Calculator_greet(self.obj_ptr, c_name)
        # C字符串转Python字符串
        return result_ptr.decode('utf-8')

    def _check_object(self):
        """检查对象是否已创建"""
        if not self.obj_ptr:
            raise RuntimeError("请先调用create()创建对象")

    def __del__(self):
        """对象销毁时自动释放C++资源"""
        if self.obj_ptr:
            self.lib.Calculator_destroy(self.obj_ptr)


if __name__ == "__main__":
    try:
        calc = CalculatorWrapper()
        calc.create(100)  # 初始化base值为100

        print(f"100 + 50 = {calc.add(50)}")  # 输出150
        print(calc.greet("C++"))  # 输出"Hello, Python"
    except Exception as e:
        print(f"错误: {e}")

4.方法补充

以下是小编整理的Python调用C++代码的其他方法,大家可以参考一下

使用ctypes调用C/C++代码

编写C/C++代码

首先,我们编写一个简单的C++函数,并将其编译为共享库(.so文件)。

// mylib.cpp
#include <iostream>
extern "C" {
    int add(int a, int b) {
        std::cout << "add called" << std::endl;
        return a + b;
    }
}

编译C/C++代码

使用以下命令将C++代码编译为共享库:

g++ -shared -o libmylib.so -fPIC mylib.cpp
  • -shared:生成共享库。
  • -o libmylib.so:指定输出文件名为libmylib.so
  • -fPIC:生成位置无关代码(Position Independent Code),这是共享库所必需的。

在Python中调用C/C++函数

使用ctypes库加载共享库并调用C++函数:

import ctypes
import os

# 加载共享库
lib = ctypes.CDLL(os.path.abspath("libmylib.so"))

# 调用 C++ 函数
result = lib.add(3, 4)  # add called
print(f"Result: {result}")  # 输出: Result: 7

使用pybind11调用C/C++代码

需要 pip install pybind11

pybind11 的名字中的 11 表示它需要 C++11 或更高版本 的支持

编写C/C++代码

pybind11是一个轻量级的C++库,用于将C++代码暴露给Python。我们编写一个简单的C++函数,并使用pybind11将其绑定到Python。

// mylib_pybind.cpp
#include <pybind11/pybind11.h>
#include <iostream>

int add(int a, int b) {
    std::cout << "add called from pybind" << std::endl;
    return a + b;
}

PYBIND11_MODULE(mylib_pybind, m) {
    m.def("add", &add, "A function that adds two numbers");
}

编译C/C++代码

使用以下命令将C++代码编译为Python模块:

c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) mylib_pybind.cpp -o mylib_pybind$(python3-config --extension-suffix)

生成了 mylib_pybind.cpython-311-x86_64-linux-gnu.so 文件

  • -O3:优化级别为3,生成高度优化的代码。
  • -Wall:启用所有警告。
  • -shared:生成共享库。
  • -std=c++11:使用C++11标准。
  • -fPIC:生成位置无关代码。
  • $(python3 -m pybind11 --includes):获取pybind11的头文件路径。
  • -o mylib_pybind$(python3-config --extension-suffix):指定输出文件名,并使用Python的扩展名后缀。

在Python中调用C/C++函数

import mylib_pybind as mylib

result = mylib.add(3, 4)  # add called from pybind
print(f"Result: {result}")  # 输出: Result: 7

c++调用python代码

# example.py
def add(a, b):
    return a + b
#include <pybind11/embed.h>  // 嵌入 Python 解释器
#include <iostream>

namespace py = pybind11;

int main() {
    // 启动 Python 解释器
    py::scoped_interpreter guard{};

    // 导入 Python 模块
    py::module_ example = py::module_::import("example");

    // 调用 Python 函数
    py::object result = example.attr("add")(3, 4);
    std::cout << "Result: " << result.cast<int>() << std::endl;  // 输出: Result: 7

    return 0;
}
g++ -o call_py call_py.cpp -I/opt/conda/envs/ai/include/python3.10/ $(python3 -m pybind11 --includes) -L/opt/conda/envs/ai/lib -lpython3.10

echo 'export LD_LIBRARY_PATH=/opt/conda/envs/ai/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

执行 ./call_py

到此这篇关于Python中调用C++代码的方法总结的文章就介绍到这了,更多相关Python调用C++代码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python中urllib模块用法实例详解

    python中urllib模块用法实例详解

    这篇文章主要介绍了python中urllib模块用法,以实例形式详细分析了python中urllib模块代替PHP的curl操作方法,具有不错的借鉴价值,需要的朋友可以参考下
    2014-11-11
  • OpenCV半小时掌握基本操作之腐蚀膨胀

    OpenCV半小时掌握基本操作之腐蚀膨胀

    这篇文章主要介绍了OpenCV基本操作之腐蚀膨胀,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Blender Python编程实现批量导入网格并保存渲染图像

    Blender Python编程实现批量导入网格并保存渲染图像

    这篇文章主要为大家介绍了Blender Python 编程实现批量导入网格并保存渲染图像示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • python银行系统实现源码

    python银行系统实现源码

    这篇文章主要为大家详细介绍了python银行系统实现源码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • Python实现删除Android工程中的冗余字符串

    Python实现删除Android工程中的冗余字符串

    这篇文章主要介绍了Python实现删除Android工程中的冗余字符串,本文实现的是删除Android资源(语言)国际化机制中的一些冗余字符串,需要的朋友可以参考下
    2015-01-01
  • Pycharm常用快捷键总结及配置方法

    Pycharm常用快捷键总结及配置方法

    这篇文章主要介绍了Pycharm常用快捷键总结及配置方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • python 简单的股票基金爬虫

    python 简单的股票基金爬虫

    最近基金非常火爆,很多原本不投资、不理财人,也开始讨论、参与买基金了。根据投资对象的不同,基金分为股票型基金、债券基金、混合型基金、货币基金。所以今天我们就来看看,这些基金公司都喜欢买那些公司的股票。
    2021-06-06
  • Python 稀疏矩阵-sparse 存储和转换

    Python 稀疏矩阵-sparse 存储和转换

    这篇文章主要介绍了Python 稀疏矩阵-sparse 存储和转换的相关资料,需要的朋友可以参考下
    2017-05-05
  • Python3.5内置模块之shelve模块、xml模块、configparser模块、hashlib、hmac模块用法分析

    Python3.5内置模块之shelve模块、xml模块、configparser模块、hashlib、hmac模块用法

    这篇文章主要介绍了Python3.5内置模块之shelve模块、xml模块、configparser模块、hashlib、hmac模块,结合实例形式较为详细的分析了shelve、xml、configparser、hashlib、hmac等模块的功能及使用方法,需要的朋友可以参考下
    2019-04-04
  • Python强化练习之PyTorch opp算法实现月球登陆器

    Python强化练习之PyTorch opp算法实现月球登陆器

    在面向对象出现之前,我们采用的开发方法都是面向过程的编程(OPP)。面向过程的编程中最常用的一个分析方法是“功能分解”。我们会把用户需求先分解成模块,然后把模块分解成大的功能,再把大的功能分解成小的功能,整个需求就是按照这样的方式,最终分解成一个一个的函数
    2021-10-10

最新评论