当前位置: 首页 > news >正文

python 调用C/C++动态库

文章目录

      • Python调用C/C++动态库详解
      • 基本原理
      • 实践案例
        • 1. 简单C函数调用示例
        • 2. 传递和返回结构体
        • 3. 处理数组和指针
        • 4. 调用C++类和函数(需要extern "C")
      • 常见问题与解决方案

Python调用C/C++动态库详解

Python通过ctypes模块可以方便地调用C/C++编写的动态库(Windows下为DLL,Linux下为SO文件)。这种方式允许Python与底层系统进行高效交互,广泛用于硬件控制、高性能计算等场景。

基本原理

  1. 动态库加载:使用ctypes.CDLL(加载C库)或ctypes.WinDLL(加载Windows特定的stdcall调用约定的DLL)加载动态库文件
  2. 函数参数与返回值类型声明:明确指定C函数的参数类型和返回值类型,确保数据传递正确
  3. 数据类型映射:将Python数据类型转换为C兼容的数据类型(如整数、字符串、结构体等)

实践案例

1. 简单C函数调用示例

C代码(保存为example.c

// example.c
#include <stdio.h>// 简单加法函数
int add(int a, int b) {return a + b;
}// 字符串处理函数
void reverse_string(char* str) {int len = 0;while (str[len] != '\0') len++;for (int i = 0; i < len/2; i++) {char temp = str[i];str[i] = str[len - i - 1];str[len - i - 1] = temp;}
}

编译为动态库

# Linux/macOS
gcc -shared -o example.so -fPIC example.c# Windows (MinGW)
gcc -shared -o example.dll example.c

Python调用代码

import ctypes# 加载动态库
lib = ctypes.CDLL('./example.so')  # Linux/macOS
# lib = ctypes.CDLL('./example.dll')  # Windows# 调用add函数
add_result = lib.add(3, 4)
print(f"3 + 4 = {add_result}")  # 输出: 7# 调用reverse_string函数
# 注意:需要传递可变的字节数组
s = ctypes.create_string_buffer(b"hello")
lib.reverse_string(s)
print(f"Reversed: {s.value.decode()}")  # 输出: olleh

在这里插入图片描述

2. 传递和返回结构体

C代码(保存为struct_example.c

#include <stdio.h>// 定义结构体
typedef struct {int x;int y;
} Point;// 结构体加法函数
Point add_points(Point a, Point b) {Point result;result.x = a.x + b.x;result.y = a.y + b.y;return result;
}// 修改结构体内容
void scale_point(Point* p, int factor) {p->x *= factor;p->y *= factor;
}

编译为动态库

gcc -shared -o struct_example.so -fPIC struct_example.c

Python调用代码

import ctypes# 加载动态库
lib = ctypes.CDLL('./struct_example.so')# 定义Point结构体
class Point(ctypes.Structure):_fields_ = [("x", ctypes.c_int),("y", ctypes.c_int)]# 设置函数参数和返回值类型
lib.add_points.argtypes = [Point, Point]
lib.add_points.restype = Pointlib.scale_point.argtypes = [ctypes.POINTER(Point), ctypes.c_int]
lib.scale_point.restype = None# 调用add_points函数
p1 = Point(1, 2)
p2 = Point(3, 4)
result = lib.add_points(p1, p2)
print(f"({p1.x}, {p1.y}) + ({p2.x}, {p2.y}) = ({result.x}, {result.y})")
# 输出: (1, 2) + (3, 4) = (4, 6)# 调用scale_point函数
p = Point(5, 6)
lib.scale_point(ctypes.byref(p), 2)
print(f"缩放后的点: ({p.x}, {p.y})")
# 输出: 缩放后的点: (10, 12)
3. 处理数组和指针

C代码(保存为array_example.c

#include <stdio.h>// 计算数组元素之和
int sum_array(int* arr, int size) {int sum = 0;for (int i = 0; i < size; i++) {sum += arr[i];}return sum;
}// 修改数组内容
void multiply_array(int* arr, int size, int factor) {for (int i = 0; i < size; i++) {arr[i] *= factor;}
}

编译为动态库

gcc -shared -o array_example.so -fPIC array_example.c

Python调用代码

import ctypes# 加载动态库
lib = ctypes.CDLL('./array_example.so')# 创建C整数数组类型
IntArray5 = ctypes.c_int * 5  # 定义长度为5的整数数组# 设置函数参数类型
lib.sum_array.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.c_int]
lib.sum_array.restype = ctypes.c_intlib.multiply_array.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_int]
lib.multiply_array.restype = None# 调用sum_array函数
arr = IntArray5(1, 2, 3, 4, 5)
sum_result = lib.sum_array(arr, 5)
print(f"数组和: {sum_result}")  # 输出: 15# 调用multiply_array函数
lib.multiply_array(arr, 5, 10)
print(f"修改后的数组: {[arr[i] for i in range(5)]}")
# 输出: [10, 20, 30, 40, 50]
4. 调用C++类和函数(需要extern “C”)

C++代码(保存为cpp_example.cpp

#include <iostream>
using namespace std;// C++类
class Calculator {
public:int add(int a, int b) { return a + b; }int subtract(int a, int b) { return a - b; }
};// 封装C++类的C接口
extern "C" {// 创建对象Calculator* Calculator_new() { return new Calculator(); }// 释放对象void Calculator_delete(Calculator* calc) { delete calc; }// 调用成员函数int Calculator_add(Calculator* calc, int a, int b) { return calc->add(a, b); }int Calculator_subtract(Calculator* calc, int a, int b) { return calc->subtract(a, b); }
}

编译为动态库

g++ -shared -o cpp_example.so -fPIC cpp_example.cpp

Python调用代码

import ctypes# 加载动态库
lib = ctypes.CDLL('./cpp_example.so')# 定义函数参数和返回值类型
lib.Calculator_new.restype = ctypes.c_void_p
lib.Calculator_delete.argtypes = [ctypes.c_void_p]
lib.Calculator_add.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
lib.Calculator_add.restype = ctypes.c_int
lib.Calculator_subtract.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
lib.Calculator_subtract.restype = ctypes.c_int# 创建Calculator对象
calc_ptr = lib.Calculator_new()# 调用成员函数
result_add = lib.Calculator_add(calc_ptr, 10, 5)
result_sub = lib.Calculator_subtract(calc_ptr, 10, 5)print(f"10 + 5 = {result_add}")  # 输出: 15
print(f"10 - 5 = {result_sub}")  # 输出: 5# 释放对象
lib.Calculator_delete(calc_ptr)

常见问题与解决方案

  1. 找不到动态库文件

    • 确保动态库文件在正确路径下
    • 使用绝对路径加载库:ctypes.CDLL('/path/to/library.so')
  2. 参数类型不匹配

    • 始终显式设置argtypesrestype
    • 对于字符串,使用ctypes.create_string_buffer()创建可变字节数组
  3. 处理C++类

    • 必须使用extern "C"封装C++接口
    • 通过指针管理对象生命周期(创建和销毁)
  4. 内存管理问题

    • 手动管理动态分配的内存(如使用delete释放C++对象)
    • 避免返回指向局部变量的指针

通过ctypes调用C/C++动态库是Python与底层系统交互的强大方式,能够在保持Python灵活性的同时获得C/C++的高性能。

http://www.lryc.cn/news/578780.html

相关文章:

  • 网络基础知识与代理配置
  • BFD故障检测技术之概述
  • 隔离网络(JAVA)
  • 2025年7月最新英雄联盟战绩自动查询工具
  • sqlmap学习笔记ing(2.[第一章 web入门]SQL注入-2(报错,时间,布尔))
  • 应急响应类题练习——玄机第四章 windows实战-emlog
  • 快速手搓一个MCP服务指南(九): FastMCP 服务器组合技术:构建模块化AI应用的终极方案
  • Spring Boot 启动加载执行链路分析
  • [Python 基础课程]字符串
  • 深度学习常见的激活函数
  • [创业之路-458]:企业经营层 - 蓝海战略 - 重构价值曲线、整合产业要素、创造新需求
  • 复现一个nanoGPT——model.py
  • Android屏幕共享+WebSocket实现传输截图
  • uniapp选择相册
  • 学习字符串
  • 菜谱大全——字符串处理艺术:从文本解析到高效搜索 [特殊字符][特殊字符]
  • LL面试题11
  • 【Python】numpy数组常用数据处理(测试代码+api例程)
  • Web前端之JavaScript实现图片圆环、圆环元素根据角度指向圆心、translate、rotate
  • vue-34(单元测试 Vue 组件的介绍)
  • 第六章 OpenCV篇—傅里叶变换与直方图
  • 通过http调用来访问neo4j时报错,curl -X POST 执行指令报错
  • 2025 推理技术风向标:DeepSeek-R1 揭示大模型从 “记忆” 到 “思考” 的进化路径
  • 8.Docker镜像讲解
  • 【读代码】百度开源大模型:ERNIE项目解析
  • 1.MySQL之如何定位慢查询
  • Python应用指南:利用高德地图API获取公交+地铁可达圈(三)
  • 达梦数据库配置SYSDBA本地免密登录
  • 怎么查看Android设备中安装的某个apk包名和启动页activity
  • CSS 安装使用教程