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++代码内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论