介紹
Python是一種高級語言,常用於快速開發、數據挖掘等領域,但有時候需要藉助C庫進行密集計算等操作。Python提供了很多種方式進行C庫調用,例如ctypes、Swig等,但各種方式都存在一些問題。CFFI是Python官方推薦的C庫調用方式,提供了原子級別的C庫調用能力,一致性強,靈活性高,效率較高,已被廣泛應用於NumPy、PyPy、Pillow等多個Python庫。
正文
一、CFFI的基礎使用
使用CFFI調用C庫的過程包括三步:
- 定義C函數介面
- 調用C函數介面
- 編譯代碼
from cffi import FFI
ffi = FFI()
lib = ffi.dlopen('libc.so.6')
# 定義C函數介面
# void 則表示沒有返回值
# int 則表示返回值類型是整數
# int, int 表示C函數接收兩個整數類型的參數
add = lib.printf
add.argtypes = ffi.typeof("char *")
add.restype = ffi.typeof("int")
# 調用C函數介面 result = add(b"Hello World") print(result)
gcc -shared -o libtest.so test.c
二、CFFI與ctypes的比較
ctypes是Python內置的C庫調用方式,也是使用比較廣泛的一種方式,但與CFFI相比還是存在一些差異:
- 使用方式:CFFI要求對C語言的代碼重構最小,而ctypes則要求用戶按照ctypes的規範來組織C代碼。
- 兼容性:CFFI兼容性良好,支持多個平台,而ctypes不一定能夠在所有平台上正常使用。
- Python版本:CFFI僅支持Python2.6、Python2.7、Python3.2以及更高版本,而ctypes作為Python內置庫則兼容Python2.6 ~ Python3.x各版本。
三、CFFI的高級使用
除了基本的C庫調用之外,CFFI還提供了一些高級功能,例如:
- Struct類型的支持
from cffi import FFI
ffi = FFI()
cpp_code = '''
#include
#include
struct PointF {
float x;
float y;
};
typedef struct PointF PointF;
void show_point(PointF p) {
printf("%0.1f, %0.1f", p.x, p.y);
}'''
# 聲明C數據結構
ffi.cdef("""
typedef struct {
float x;
float y;
} PointF;
void show_point(PointF);
""")
lib = ffi.verify(cpp_code, libraries=[])
p = ffi.new('PointF*', [1.5, 2.4])
lib.show_point(p[0])from cffi import FFI
ffi = FFI()
cpp_code = '''
#include
union Shape {
int shape_type;
struct {
int x;
int y;
int width;
int height;
} rect;
};
typedef union Shape Shape;
void show_rect(Shape r) {
printf("(%d, %d, %d, %d)",
r.rect.x, r.rect.y, r.rect.width, r.rect.height);
}'''
ffi.cdef("""
typedef union {
int shape_type;
struct {
int x;
int y;
int width;
int height;
} rect;
} Shape;
void show_rect(Shape);
""")
lib = ffi.verify(cpp_code, libraries=[])
s = ffi.new('Shape*', [0])
s.rect.x = 1
s.rect.y = 2
s.rect.width = 3
s.rect.height = 4
lib.show_rect(s[0])代碼部分
以下是一個使用CFFI調用Windows API的例子:
# -*- coding: utf-8 -*-
from cffi import FFI
# 定義C函數介面
ffi = FFI()
ffi.cdef("""
typedef struct _FILETIME {
unsigned long dwLowDateTime;
unsigned long dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
typedef struct _SYSTEMTIME {
short wYear;
short wMonth;
short wDayOfWeek;
short wDay;
short wHour;
short wMinute;
short wSecond;
short wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
void GetSystemTime(SYSTEMTIME *lpSystemTime);
void SystemTimeToFileTime(const SYSTEMTIME *lpSystemTime, LPFILETIME lpFileTime);
void FileTimeToLocalFileTime(CONST FILETIME *lpFileTime, LPFILETIME lpLocalFileTime);
BOOL FileTimeToSystemTime(const FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime);
""")
lib = ffi.dlopen('kernel32.dll')
# 調用GetSystemTime函數,獲取當前系統時間(UTC)
system_time = ffi.new('SYSTEMTIME *')
lib.GetSystemTime(system_time)
# 將UTC時間轉換為本地時間
file_time_utc = ffi.new('FILETIME *')
lib.SystemTimeToFileTime(system_time, file_time_utc)
file_time_local = ffi.new('FILETIME *')
lib.FileTimeToLocalFileTime(file_time_utc, file_time_local)
# 獲取系統時間(本地時間)
local_time = ffi.new('SYSTEMTIME *')
lib.FileTimeToSystemTime(file_time_local, local_time)
print('Local Time:', local_time.wYear, local_time.wMonth, local_time.wDay, local_time.wHour, local_time.wMinute, local_time.wSecond, local_time.wMilliseconds)原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/257975.html
微信掃一掃
支付寶掃一掃