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

作者:

文章目录
  • Python通过ctypes模块可以方便地调用C/C++编写的动态库(Windows下为DLL,Linux下为SO文件)。这种方式允许Python与底层系统进行高效交互,广泛用于硬件控制、高性能计算等场景。
  • 动态库加载:使用ctypes.CDLL(加载C库)或ctypes.WinDLL(加载Windows特定的stdcall调用约定的DLL)加载动态库文件 函数参数与返回值类型声明:明确指定C函数的参数类型和返回值类型,确保数据传递正确 数据类型映射:将Python数据类型转换为C兼容的数据类型(如整数、字符串、结构体等)
  • 找不到动态库文件 确保动态库文件在正确路径下 使用绝对路径加载库:ctypes.CDLL('/path/to/library.so') 参数类型不匹配 始终显式设置argtypes和restype 对于字符串,使用ctypes.create_string_buffer()创建可变字节数组 处理C++类 必须使用extern "C"封装C++接口 通过指针管理对象生命周期(创建和销毁) 内存管理问题 手动管理动态分配的内存(如使用delete释放C++对象) 避免返回指向局部变量的指针 通过ctypes调用C/C++动态库是Python与底层系统交互的强大方式,能够在保持Python灵活性的同时获得C/C++的高性能。
  • 到此这篇关于python调用C/C++动态库的文章就介绍到这了,更多相关python调用C/C++动态库内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: 关于python调用c++动态库dll时的参数传递问题 linux中使用boost.python调用c++动态库的方法 python模块与C和C++动态库相互调用实现过程示例 Python调用C++动态库详细步骤(附源码)
  • 目录
    • 前言
    • 基本原理
    • 实践案例
      • 1. 简单C函数调用示例
      • 2. 传递和返回结构体
      • 3. 处理数组和指针
      • 4. 调用C++类和函数(需要extern “C”)
    • 常见问题与解决方案
      • 总结

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

        1. 动态库加载:使用ctypes.CDLL(加载C库)或ctypes.WinDLL(加载Windows特定的stdcall调用约定的DLL)加载动态库文件
        2. 函数参数与返回值类型声明:明确指定C函数的参数类型和返回值类型,确保数据传递正确
        3. 数据类型映射:将Python数据类型转换为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] != '') 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
        

        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)
        

        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]
        

        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++动态库内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

        您可能感兴趣的文章:

        • 关于python调用c++动态库dll时的参数传递问题
        • linux中使用boost.python调用c++动态库的方法
        • python模块与C和C++动态库相互调用实现过程示例
        • Python调用C++动态库详细步骤(附源码)

        站内搜索