看板 Python 關於我們 聯絡資訊
抱歉爬了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)) 但想請教一下這樣是為甚麼報錯呢? -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.235.222.156 ※ 文章網址: http://www.ptt.cc/bbs/Python/M.1408028735.A.1EB.html ※ 編輯: dctzeng (111.243.146.150), 08/14/2014 23:39:41
LiloHuang: 如果要在 Python 內操作資料,資料通常都得做搬動的 08/14 23:35
LiloHuang: 我猜你應該是想要做以下的事情...我先把問題簡化 08/14 23:35
LiloHuang: 假設使用 addr = ctypes.cdll.msvcrt.malloc(1024) 08/14 23:36
LiloHuang: 得到一個記憶體位置為 addr,類似你的GetBufferAddress 08/14 23:36
LiloHuang: 如果我先用 memmove(addr, "\xFF\xFF\x00\x00", 4) 08/14 23:36
LiloHuang: 此時應該會寫入 4 byte 的資料,考慮 little endian 08/14 23:37
LiloHuang: cast(x, POINTER(c_int)).contents.value 會讀出 65535 08/14 23:37
LiloHuang: 抱歉上面的 x 是指 addr 的意思,推文實在塞不下 08/14 23:38
LiloHuang: 再次更正 x = c_void_p(addr) 08/14 23:39
LiloHuang: 使用 c_void_p(addr) 的方式將你的指標塞進去後 08/14 23:40
LiloHuang: 就可以用 cast 搭配 contents.value 的方式來做存取了 08/14 23:41
dctzeng: 那在python宣告記憶體,把位址傳給dll去處理會省copy嗎? 08/14 23:42
LiloHuang: 這樣記憶體就是由 Python runtime 幫你管理 08/14 23:44
dctzeng: 例如宣告1MB string 把位址當參數給dll當char* 處理好嗎 08/14 23:44
LiloHuang: 至於拷貝看是拷貝什麼,畢竟很多東西都得變 PyObject 08/14 23:44
LiloHuang: 可以的呀,正常操作狀況不會一直拷貝那 1MB 的 08/14 23:45
dctzeng: 但其實string 不是char*,是硬碟任意資料 fd.Read() 來的 08/14 23:45
dctzeng: 就是 fd.Read()讀一坨資料; dll讀一坨資料,兩個相比而已 08/14 23:47
LiloHuang: 你可以看看 byref, addressof, cast 這幾個的用法 08/14 23:47
LiloHuang: 資料從 Python 跟 C API 做交換,ctypes 會有一些成本 08/14 23:48
dctzeng: 只是資料量大而且多thread要長時間跑,很不想額外memcpy 08/14 23:48
LiloHuang: 當你東西是使用指標 (也就是我上面的範例) 算快的做法 08/14 23:48
LiloHuang: 如果是我寫我會盡量讓 Python runtime 來幫我管記憶體 08/14 23:49
LiloHuang: 當然還是得看場合,到底是誰該擺那一塊記憶體... 08/14 23:51
LiloHuang: 好比說用 create_string_buffer 來產生 buffer object 08/14 23:52
dctzeng: 那1MB會重複一直讀出來是因為那是dll的buffer,會重複更新 08/14 23:54
LiloHuang: 不好意思我現在看到你修改後的文章了... 08/14 23:55
dctzeng: 喔~ 不會 看到你提一些關鍵字沒用過,google查一查 偷學 08/14 23:56
LiloHuang: 那我重新修正,如果你只是想要比較用 c_char_p 就好 08/15 00:08
LiloHuang: foo = 'x'*1024*1024*100 # 記憶體耗用 100 MB 左右 08/15 00:09
LiloHuang: bar = c_char_p(foo) # 這個動作不會拷貝 100MB 08/15 00:09
LiloHuang: ctypes.memmove(bar, "test", 4) # 硬是修改 foo 字串 08/15 00:09
LiloHuang: # 雷同於你傳入 DLL 08/15 00:10
LiloHuang: print foo[0:10] # 順便再印出 foo 的一部分觀察 08/15 00:10
LiloHuang: 以上的 foo 類似於你從 fd.read 讀出的字串結果 08/15 00:11
LiloHuang: ctypes.memmove 類似於你帶入 DLL 的部分,試試看囉 08/15 00:12
LiloHuang: 可搭配 ProcessExplorer 選 python.exe 觀察記憶體用量 08/15 00:14
我試試 先謝謝 ※ 編輯: dctzeng (111.243.146.150), 08/15/2014 00:23:42
LiloHuang: 順便回你文章的那個問題,那個寫法應該也不會拷貝資料 08/15 00:41
LiloHuang: 至於之所以會出錯的原因是 from_address 是吃 integer 08/15 00:42
LiloHuang: 用了 hex 就變成了字串,錯誤訊息是指參數型別不正確 08/15 00:43
LiloHuang: 這種做法也是拿一個指標來操作的做法,都相當的快速 08/15 00:44
※ 編輯: dctzeng (111.243.146.150), 08/15/2014 01:06:02