python中ctypes使用方法
前段時間接到了一個需求是給一個藍牙的SDK測試接口的穩(wěn)定性,將SDK的接口文檔給你了,需要每個接口都寫一個對應的測試用例,SDK 是用c寫的,而我python用的比較熟練些,所有記錄下在ctypes庫的使用方法。
1 python和c中類型映射
ctypes中數據類型
| ctypes 類型 | C 類型 | Python 數據類型 |
|---|---|---|
| c_bool | _Bool | bool (1) |
| c_char | char | 單字符字節(jié)串對象 |
| c_wchar | wchar_t | 單字符字符串 |
| c_byte | char | int |
| c_ubyte | unsigned char | int |
| POINTER(c_ubyte) | uchar* | int |
| c_short | short | int |
| c_ushort | unsigned short | int |
| c_int | int | int |
| c_uint | unsigned int | int |
| c_long | long | int |
| c_ulong | unsigned long | int |
| c_longlong | __int64 或 long long | int |
| c_ulonglong | unsigned __int64 或 unsigned long long | int |
| c_size_t | size_t | int |
| c_ssize_t | ssize_t 或 Py_ssize_t | int |
| c_float | float | float |
| c_double | double | float |
| c_longdouble | long double | float |
| c_char_p | char * (NUL terminated) | 字節(jié)串對象或 None |
| c_wchar_p | wchar_t * (NUL terminated) | 字符串或 None |
| c_void_p | void * | int 或 None |
2 加載共享庫
import ctypes
# 加載本地的共享庫,路徑根據實際情況調整
lib = ctypes.CDLL('./libexample.so') # Linux/macOS平臺
# lib = ctypes.WinDLL('example.dll') # Windows平臺3 調用函數
# 設置參數類型 lib.add.argtypes = [ctypes.c_int, ctypes.c_int] # 設置返回類型 lib.add.restype = ctypes.c_int # 調用C函數 result = lib.add(2, 3) print(result) # 輸出:5
4 操作指針
在ctypes中,你可以使用pointer和byref來操作指針。
# 創(chuàng)建一個整數數組 arr = (ctypes.c_int * 5)(1, 2, 3, 4, 5) # 獲取指向數組首元素的指針 ptr = ctypes.pointer(arr) # 通過指針訪問數組元素 print(ptr[0]) # 輸出:1 # 使用byref創(chuàng)建指向變量的指針 x = ctypes.c_int(10) px = ctypes.byref(x) # 通過指針修改變量的值 lib.increment(px) # 假設有一個increment函數用于增加整數的值 print(x.value) # 輸出:11
# 調用系統的庫函數測試
from ctypes import c_int, c_float, create_string_buffer, CDLL, byref
c_lib = CDLL('/lib/x86_64-linux-gnu/libc.so.6')
i = c_int()
f = c_float()
s = create_string_buffer(b"\000" * 32)
print(i.value, f.value, repr(s.value))
# brref 傳入數據類型返回指針的地址, create_string_buffer返回的是指針
c_lib.sscanf(b"1 3.14 Hello", b"%d %f %s", byref(i), byref(f), s)
print(i.value, f.value, repr(s.value))from ctypes import c_int, POINTER, cdll
i = c_int(42) # 創(chuàng)建一個int類型變量
pi = POINTER(c_int)(i) # 定義一個指向int類型的指針
print(pi.contents) # 打印指針指向的內存地址
print(pi.contents.value) # 打印指針指向的值
# 定義C庫中的函數原型
sum_func = cdll.LoadLibrary('./test1.so').sums
sum_func.argtypes = [POINTER(c_int), POINTER(c_int)] # 定義函數參數類型為指針類型
sum_func.restype = POINTER(c_int) # 定義函數返回值類型為指針類型
pointer = POINTER(c_int)
# 調用sum()函數
a = c_int(1)
b = c_int(2)
c = sum_func(pointer(a), pointer(b)) # 將a、b的地址傳遞給sum()函數
print(c.contents.value) # 打印返回值5 操作結構體和聯合體
你需要定義結構體或聯合體的類型,然后可以創(chuàng)建實例、訪問其成員等。
# 定義C語言的結構體類型
class Point(ctypes.Structure):
_fields_ = [("x", ctypes.c_int), ("y", ctypes.c_int)]
# 創(chuàng)建結構體的實例
p = Point()
p.x = 10
p.y = 20
# 將結構體的實例傳遞給C函數
lib.print_point(p) # 假設有一個print_point函數用于打印點的坐標6 處理字符串
字符串通常以字符數組或字符指針的形式存在。在ctypes中,你可以使用create_string_buffer來創(chuàng)建C風格的字符串,或者使用c_char_p來操作字符串指針。
# 創(chuàng)建C風格的字符串 c_str = ctypes.create_string_buffer(b"Hello, World!") # 將字符串傳遞給C函數 lib.print_string(c_str) # 假設有一個print_string函數用于打印字符串 # 處理C語言中的字符串指針 c_char_p_type = ctypes.POINTER(ctypes.c_char) c_char_p = c_char_p_type.from_buffer(c_str) lib.print_string_ptr(c_char_p) # 假設有一個print_string_ptr函數接收字符串指針
7 回調函數
c 中很多實現異步的方式通過回調函數事件觸發(fā)的方式,ctype中也能將ctype定義的函數傳入c中執(zhí)行
# include "stdio.h"
typedef int (*CallbackFunc)(int, int);
int c_sub(int x, int y){
printf("c callback func\n");
return x - y;
}
void call_callback(CallbackFunc callback){
int result = callback(3, 4);
printf("result from c: %d\n", result);
}import ctypes
my_lib = ctypes.CDLL("./test2.so")
callback_type = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int)
def python_sub(a, b):
print("python callback func")
return b - a
# 1.調用c中的函數,回調函數從python中傳入
python_callback = callback_type(python_sub)
my_lib.call_callback(python_callback)
# 2.調用c中的函數,回調從c中傳入
c_callback = callback_type(my_lib.c_sub)
my_lib.call_callback(c_callback)到此這篇關于python中ctypes使用的文章就介紹到這了,更多相關python ctypes使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
python獲取微信企業(yè)號打卡數據并生成windows計劃任務
由于公司的系統用的是Java版本,開通了企業(yè)號打卡之后又沒有預算讓供應商做數據對接,所以只能自己搗鼓這個,以下是個人設置的一些內容,僅供大家參考2019-04-04
Python+tkinter使用80行代碼實現一個計算器實例
這篇文章主要介紹了Python+tkinter使用80行代碼實現一個計算器實例,具有一定借鑒價值,需要的朋友可以參考下2018-01-01
Python代碼集pathlib應用之獲取指定目錄下的所有文件
這篇文章主要介紹了Python代碼集pathlib應用之獲取指定目錄下的所有文件,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03

