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

Written by

in

文章目录
  • // 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(); } }
  • # 使用C++编译器,保留 -f PIC -shared 参数生成位置无关的动态库 g++ -shared -fPIC -o libcalc.so example.cpp
  • 使用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}”)
  • 以下是小编整理的Python调用C++代码的其他方法,大家可以参考一下
  • 目录
    • 1. extern "C" {} 包裹导出函数
    • 2. 将C++代码编译为动态库
    • 3.python ctypes调用动态库
    • 4.方法补充
      • 使用ctypes调用C/C++代码
      • 使用pybind11调用C/C++代码
      • c++调用python代码

    // 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();
    }
    
    }
    

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

    使用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}")
    
    

    以下是小编整理的Python调用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
    

    需要 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
    

    # 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调用C/C++动态库的实践案例
    • Python调用C/C++函数库的多种方法与实践指南
    • Python调用C++动态库详细步骤(附源码)
    • C++如何调用python并取返回值
    • 在python中调用C/C++的三种方法
    • C++如何调用简单的python程序
    • python 与c++相互调用实现

    站内搜索