python中ctypes使用方法
前段時(shí)間接到了一個(gè)需求是給一個(gè)藍(lán)牙的SDK測(cè)試接口的穩(wěn)定性,將SDK的接口文檔給你了,需要每個(gè)接口都寫一個(gè)對(duì)應(yīng)的測(cè)試用例,SDK 是用c寫的,而我python用的比較熟練些,所有記錄下在ctypes庫(kù)的使用方法。
1 python和c中類型映射
ctypes中數(shù)據(jù)類型
ctypes 類型 | C 類型 | Python 數(shù)據(jù)類型 |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 單字符字節(jié)串對(duì)象 |
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é)串對(duì)象或 None |
c_wchar_p | wchar_t * (NUL terminated) | 字符串或 None |
c_void_p | void * | int 或 None |
2 加載共享庫(kù)
import ctypes # 加載本地的共享庫(kù),路徑根據(jù)實(shí)際情況調(diào)整 lib = ctypes.CDLL('./libexample.so') # Linux/macOS平臺(tái) # lib = ctypes.WinDLL('example.dll') # Windows平臺(tái)
3 調(diào)用函數(shù)
# 設(shè)置參數(shù)類型 lib.add.argtypes = [ctypes.c_int, ctypes.c_int] # 設(shè)置返回類型 lib.add.restype = ctypes.c_int # 調(diào)用C函數(shù) result = lib.add(2, 3) print(result) # 輸出:5
4 操作指針
在ctypes中,你可以使用pointer和byref來(lái)操作指針。
# 創(chuàng)建一個(gè)整數(shù)數(shù)組 arr = (ctypes.c_int * 5)(1, 2, 3, 4, 5) # 獲取指向數(shù)組首元素的指針 ptr = ctypes.pointer(arr) # 通過(guò)指針訪問(wèn)數(shù)組元素 print(ptr[0]) # 輸出:1 # 使用byref創(chuàng)建指向變量的指針 x = ctypes.c_int(10) px = ctypes.byref(x) # 通過(guò)指針修改變量的值 lib.increment(px) # 假設(shè)有一個(gè)increment函數(shù)用于增加整數(shù)的值 print(x.value) # 輸出:11
# 調(diào)用系統(tǒng)的庫(kù)函數(shù)測(cè)試 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 傳入數(shù)據(jù)類型返回指針的地址, 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)建一個(gè)int類型變量 pi = POINTER(c_int)(i) # 定義一個(gè)指向int類型的指針 print(pi.contents) # 打印指針指向的內(nèi)存地址 print(pi.contents.value) # 打印指針指向的值 # 定義C庫(kù)中的函數(shù)原型 sum_func = cdll.LoadLibrary('./test1.so').sums sum_func.argtypes = [POINTER(c_int), POINTER(c_int)] # 定義函數(shù)參數(shù)類型為指針類型 sum_func.restype = POINTER(c_int) # 定義函數(shù)返回值類型為指針類型 pointer = POINTER(c_int) # 調(diào)用sum()函數(shù) a = c_int(1) b = c_int(2) c = sum_func(pointer(a), pointer(b)) # 將a、b的地址傳遞給sum()函數(shù) print(c.contents.value) # 打印返回值
5 操作結(jié)構(gòu)體和聯(lián)合體
你需要定義結(jié)構(gòu)體或聯(lián)合體的類型,然后可以創(chuàng)建實(shí)例、訪問(wèn)其成員等。
# 定義C語(yǔ)言的結(jié)構(gòu)體類型 class Point(ctypes.Structure): _fields_ = [("x", ctypes.c_int), ("y", ctypes.c_int)] # 創(chuàng)建結(jié)構(gòu)體的實(shí)例 p = Point() p.x = 10 p.y = 20 # 將結(jié)構(gòu)體的實(shí)例傳遞給C函數(shù) lib.print_point(p) # 假設(shè)有一個(gè)print_point函數(shù)用于打印點(diǎn)的坐標(biāo)
6 處理字符串
字符串通常以字符數(shù)組或字符指針的形式存在。在ctypes中,你可以使用create_string_buffer來(lái)創(chuàng)建C風(fēng)格的字符串,或者使用c_char_p來(lái)操作字符串指針。
# 創(chuàng)建C風(fēng)格的字符串 c_str = ctypes.create_string_buffer(b"Hello, World!") # 將字符串傳遞給C函數(shù) lib.print_string(c_str) # 假設(shè)有一個(gè)print_string函數(shù)用于打印字符串 # 處理C語(yǔ)言中的字符串指針 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) # 假設(shè)有一個(gè)print_string_ptr函數(shù)接收字符串指針
7 回調(diào)函數(shù)
c 中很多實(shí)現(xiàn)異步的方式通過(guò)回調(diào)函數(shù)事件觸發(fā)的方式,ctype中也能將ctype定義的函數(shù)傳入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.調(diào)用c中的函數(shù),回調(diào)函數(shù)從python中傳入 python_callback = callback_type(python_sub) my_lib.call_callback(python_callback) # 2.調(diào)用c中的函數(shù),回調(diào)從c中傳入 c_callback = callback_type(my_lib.c_sub) my_lib.call_callback(c_callback)
到此這篇關(guān)于python中ctypes使用的文章就介紹到這了,更多相關(guān)python ctypes使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python獲取微信企業(yè)號(hào)打卡數(shù)據(jù)并生成windows計(jì)劃任務(wù)
由于公司的系統(tǒng)用的是Java版本,開(kāi)通了企業(yè)號(hào)打卡之后又沒(méi)有預(yù)算讓供應(yīng)商做數(shù)據(jù)對(duì)接,所以只能自己搗鼓這個(gè),以下是個(gè)人設(shè)置的一些內(nèi)容,僅供大家參考2019-04-04使用Django清空數(shù)據(jù)庫(kù)并重新生成
這篇文章主要介紹了使用Django清空數(shù)據(jù)庫(kù)并重新生成,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04Pandas+openpyxl進(jìn)行Excel處理詳解
這篇文章主要為大家詳細(xì)介紹了如何使用pandas和openpyxl庫(kù)對(duì)多個(gè)Excel文件進(jìn)行多種處理的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2025-02-02Python+tkinter使用80行代碼實(shí)現(xiàn)一個(gè)計(jì)算器實(shí)例
這篇文章主要介紹了Python+tkinter使用80行代碼實(shí)現(xiàn)一個(gè)計(jì)算器實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01Python 刪除連續(xù)出現(xiàn)的指定字符的實(shí)例
今天小編就為大家分享一篇Python 刪除連續(xù)出現(xiàn)的指定字符的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Python代碼集pathlib應(yīng)用之獲取指定目錄下的所有文件
這篇文章主要介紹了Python代碼集pathlib應(yīng)用之獲取指定目錄下的所有文件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03python鏈接oracle數(shù)據(jù)庫(kù)以及數(shù)據(jù)庫(kù)的增刪改查實(shí)例
下面小編就為大家分享一篇python鏈接oracle數(shù)據(jù)庫(kù)以及數(shù)據(jù)庫(kù)的增刪改查實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01Python正則表達(dá)式匹配數(shù)字和小數(shù)的方法
這篇文章主要介紹了Python正則匹配數(shù)字和小數(shù)的方法,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07對(duì)python3標(biāo)準(zhǔn)庫(kù)httpclient的使用詳解
今天小編就為大家分享一篇對(duì)python3標(biāo)準(zhǔn)庫(kù)httpclient的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12