[問題] 請教處理ctypes dll 回傳 c_ubyte_p 問題

作者: dctzeng (DC)   2014-08-14 23:05:32
抱歉爬了google找不太到的樣子,來這找高手大大
import ctypes 外部的dll
C code 類似:
static char gp_huge_buffer[1024][1024];
unsigned char *GetBufferAddress(void){
//change gp_huge_buffer contain
return (unsigned char *)gp_huge_buffer;
}
Python 類似去呼叫dll:
mydll = ctypes.cdll.LoadLibrary(path)
mydll.GetBufferAddress.argtypes = []
mydll.GetBufferAddress.restype = ctypes.POINTER(ctypes.c_ubyte)
# Google找到的,好像是在python中拷貝一份,而且好像不能用
p_ubyte = mydll.GetBufferAddress()
byte_array = c_ubyte * buffer_size
bytes = byte_array.from_address(hex(p_ubyte)) # error ! LP_c_ubyte cannot be
# interreted as integer
因為存資料的 buffer 是在 dll 中配置的,C 資料放進去想和 python 的 fd.read()比對
為了速度和記憶體考量下不想在python再重新從dll拷貝出來
請問有辦法向C語言直接拿pointer存取GetBufferAddress回傳位址中的任意byte嗎?
ps 雖然不想用 bytes = byte_array.from_address(hex(p_ubyte))
但想請教一下這樣是為甚麼報錯呢?
作者: LiloHuang (十年一刻)   2014-08-14 23:35:00
如果要在 Python 內操作資料,資料通常都得做搬動的我猜你應該是想要做以下的事情...我先把問題簡化假設使用 addr = ctypes.cdll.msvcrt.malloc(1024)得到一個記憶體位置為 addr,類似你的GetBufferAddress如果我先用 memmove(addr, "\xFF\xFF\x00\x00", 4)此時應該會寫入 4 byte 的資料,考慮 little endiancast(x, POINTER(c_int)).contents.value 會讀出 65535抱歉上面的 x 是指 addr 的意思,推文實在塞不下再次更正 x = c_void_p(addr)使用 c_void_p(addr) 的方式將你的指標塞進去後就可以用 cast 搭配 contents.value 的方式來做存取了
作者: dctzeng (DC)   2014-08-14 23:42:00
那在python宣告記憶體,把位址傳給dll去處理會省copy嗎?
作者: LiloHuang (十年一刻)   2014-08-14 23:44:00
這樣記憶體就是由 Python runtime 幫你管理
作者: dctzeng (DC)   2014-08-14 23:44:00
例如宣告1MB string 把位址當參數給dll當char* 處理好嗎
作者: dctzeng (DC)   2014-08-14 23:45:00
但其實string 不是char*,是硬碟任意資料 fd.Read() 來的就是 fd.Read()讀一坨資料; dll讀一坨資料,兩個相比而已
作者: LiloHuang (十年一刻)   2014-08-14 23:47:00
你可以看看 byref, addressof, cast 這幾個的用法資料從 Python 跟 C API 做交換,ctypes 會有一些成本
作者: dctzeng (DC)   2014-08-14 23:48:00
只是資料量大而且多thread要長時間跑,很不想額外memcpy
作者: LiloHuang (十年一刻)   2014-08-14 23:48:00
當你東西是使用指標 (也就是我上面的範例) 算快的做法如果是我寫我會盡量讓 Python runtime 來幫我管記憶體當然還是得看場合,到底是誰該擺那一塊記憶體...好比說用 create_string_buffer 來產生 buffer object
作者: dctzeng (DC)   2014-08-14 23:54:00
那1MB會重複一直讀出來是因為那是dll的buffer,會重複更新
作者: LiloHuang (十年一刻)   2014-08-14 23:55:00
不好意思我現在看到你修改後的文章了...
作者: dctzeng (DC)   2014-08-14 23:56:00
喔~ 不會 看到你提一些關鍵字沒用過,google查一查 偷學
作者: LiloHuang (十年一刻)   2014-08-15 00:08:00
那我重新修正,如果你只是想要比較用 c_char_p 就好foo = 'x'*1024*1024*100 # 記憶體耗用 100 MB 左右bar = c_char_p(foo) # 這個動作不會拷貝 100MBctypes.memmove(bar, "test", 4) # 硬是修改 foo 字串# 雷同於你傳入 DLLprint foo[0:10] # 順便再印出 foo 的一部分觀察以上的 foo 類似於你從 fd.read 讀出的字串結果ctypes.memmove 類似於你帶入 DLL 的部分,試試看囉可搭配 ProcessExplorer 選 python.exe 觀察記憶體用量順便回你文章的那個問題,那個寫法應該也不會拷貝資料至於之所以會出錯的原因是 from_address 是吃 integer用了 hex 就變成了字串,錯誤訊息是指參數型別不正確這種做法也是拿一個指標來操作的做法,都相當的快速

Links booklink

Contact Us: admin [ a t ] ucptt.com