python調用C/C++動態(tài)庫的實踐案例
前言
Python通過ctypes模塊可以方便地調用C/C++編寫的動態(tài)庫(Windows下為DLL,Linux下為SO文件)。這種方式允許Python與底層系統進行高效交互,廣泛用于硬件控制、高性能計算等場景。
基本原理
- 動態(tài)庫加載:使用
ctypes.CDLL(加載C庫)或ctypes.WinDLL(加載Windows特定的stdcall調用約定的DLL)加載動態(tài)庫文件 - 函數參數與返回值類型聲明:明確指定C函數的參數類型和返回值類型,確保數據傳遞正確
- 數據類型映射:將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;
}
}
編譯為動態(tài)庫:
# Linux/macOS gcc -shared -o example.so -fPIC example.c # Windows (MinGW) gcc -shared -o example.dll example.c
Python調用代碼:
import ctypes
# 加載動態(tài)庫
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函數
# 注意:需要傳遞可變的字節(jié)數組
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;
}
編譯為動態(tài)庫:
gcc -shared -o struct_example.so -fPIC struct_example.c
Python調用代碼:
import ctypes
# 加載動態(tài)庫
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;
}
}
編譯為動態(tài)庫:
gcc -shared -o array_example.so -fPIC array_example.c
Python調用代碼:
import ctypes
# 加載動態(tài)庫
lib = ctypes.CDLL('./array_example.so')
# 創(chuàng)建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" {
// 創(chuàng)建對象
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); }
}
編譯為動態(tài)庫:
g++ -shared -o cpp_example.so -fPIC cpp_example.cpp
Python調用代碼:
import ctypes
# 加載動態(tài)庫
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
# 創(chuàng)建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)
常見問題與解決方案
找不到動態(tài)庫文件
- 確保動態(tài)庫文件在正確路徑下
- 使用絕對路徑加載庫:
ctypes.CDLL('/path/to/library.so')
參數類型不匹配
- 始終顯式設置
argtypes和restype - 對于字符串,使用
ctypes.create_string_buffer()創(chuàng)建可變字節(jié)數組
- 始終顯式設置
處理C++類
- 必須使用
extern "C"封裝C++接口 - 通過指針管理對象生命周期(創(chuàng)建和銷毀)
- 必須使用
內存管理問題
- 手動管理動態(tài)分配的內存(如使用
delete釋放C++對象) - 避免返回指向局部變量的指針
- 手動管理動態(tài)分配的內存(如使用
通過ctypes調用C/C++動態(tài)庫是Python與底層系統交互的強大方式,能夠在保持Python靈活性的同時獲得C/C++的高性能。
總結
到此這篇關于python調用C/C++動態(tài)庫的文章就介紹到這了,更多相關python調用C/C++動態(tài)庫內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
docker-py 用Python調用Docker接口的方法
今天小編就為大家分享一篇docker-py 用Python調用Docker接口的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08
Python中的aa-whisper包語法、參數和實際應用案例小結
aa-whisper是基于Whisper的增強工具包,支持99種語言、實時語音處理、批量轉換及多種輸出格式,本文給大家介紹Python中的aa-whisper包語法、參數和實際應用案例小結,感興趣的朋友一起看看吧2025-09-09

