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库调用动态库(加载动态库 -> 定义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}")