python调用C/C++动态库的实践案例

 更新时间:2025年09月30日 09:37:59   作者:越甲八千  
python是动态语言,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 = Point

lib.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_int

lib.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++的高性能。

总结

到此这篇关于python调用C/C++动态库的文章就介绍到这了,更多相关python调用C/C++动态库内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • windows上安装python3教程以及环境变量配置详解

    windows上安装python3教程以及环境变量配置详解

    这篇文章主要介绍了windows上安装python3教程以及环境变量配置详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • python人工智能算法之人工神经网络

    python人工智能算法之人工神经网络

    这篇文章主要为大家介绍了python人工智能算法之人工神经网络示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • 安装conda搭建python环境保姆级教程(超详细!)

    安装conda搭建python环境保姆级教程(超详细!)

    这篇文章主要给大家介绍了关于安装conda搭建python环境保姆级教程的相关资料,conda可以理解为一个工具,也是一个可执行命令,其核心功能是包管理和环境管理,需要的朋友可以参考下
    2023-11-11
  • 浅析Python编写函数装饰器

    浅析Python编写函数装饰器

    这篇文章主要介绍了Python编写函数装饰器的相关资料,需要的朋友可以参考下
    2016-03-03
  • 一文了解Django缓存机制

    一文了解Django缓存机制

    本文主要介绍了一文了解Django缓存机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Python深度学习之Unet 语义分割模型(Keras)

    Python深度学习之Unet 语义分割模型(Keras)

    这篇文章主要介绍了语义分割任务中Unet一个有意思的模型-Keras。Keras是一个由Python编写的开源人工神经网络库,可进行深度学习模型的设计、调试、评估、应用和可视化。感兴趣的小伙伴快来跟随小编一起学习一下吧
    2021-12-12
  • python GUI库图形界面开发之PyQt5 UI主线程与耗时线程分离详细方法实例

    python GUI库图形界面开发之PyQt5 UI主线程与耗时线程分离详细方法实例

    这篇文章主要介绍了python GUI库图形界面开发之PyQt5 UI主线程与耗时线程分离详细方法实例,需要的朋友可以参考下
    2020-02-02
  • Python中对字典的几个处理方法分享

    Python中对字典的几个处理方法分享

    这篇文章主要介绍了Python中对字典的几个处理方法分享,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下
    2022-08-08
  • Python实现弹球小游戏的示例代码

    Python实现弹球小游戏的示例代码

    这篇文章主要为大家详细介绍了Python如何实现简单的弹球小游戏,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2022-11-11
  • 使用Python找出水仙花数的方法介绍

    使用Python找出水仙花数的方法介绍

    水仙花数也被称为超完全数字不变数、自恋数、自幂数、阿姆斯壮数或阿姆斯特朗数,水仙花数是指一个3位数,本文就给大家简单聊聊如何使用Python找出水仙花数,感兴趣的同学可以参考阅读
    2023-07-07

最新评论