作者dctzeng (DC)
看板Python
标题[问题] 请教处理ctypes dll 回传 c_ubyte_p 问题
时间Thu Aug 14 23:05:32 2014
抱歉爬了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://webptt.com/cn.aspx?n=bbs/Python/M.1408028735.A.1EB.html
※ 编辑: dctzeng (111.243.146.150), 08/14/2014 23:39:41
1F:推 LiloHuang: 如果要在 Python 内操作资料,资料通常都得做搬动的 08/14 23:35
2F:→ LiloHuang: 我猜你应该是想要做以下的事情...我先把问题简化 08/14 23:35
3F:→ LiloHuang: 假设使用 addr = ctypes.cdll.msvcrt.malloc(1024) 08/14 23:36
4F:→ LiloHuang: 得到一个记忆体位置为 addr,类似你的GetBufferAddress 08/14 23:36
5F:→ LiloHuang: 如果我先用 memmove(addr, "\xFF\xFF\x00\x00", 4) 08/14 23:36
6F:→ LiloHuang: 此时应该会写入 4 byte 的资料,考虑 little endian 08/14 23:37
7F:→ LiloHuang: cast(x, POINTER(c_int)).contents.value 会读出 65535 08/14 23:37
8F:→ LiloHuang: 抱歉上面的 x 是指 addr 的意思,推文实在塞不下 08/14 23:38
9F:→ LiloHuang: 再次更正 x = c_void_p(addr) 08/14 23:39
10F:→ LiloHuang: 使用 c_void_p(addr) 的方式将你的指标塞进去後 08/14 23:40
11F:→ LiloHuang: 就可以用 cast 搭配 contents.value 的方式来做存取了 08/14 23:41
12F:→ dctzeng: 那在python宣告记忆体,把位址传给dll去处理会省copy吗? 08/14 23:42
13F:推 LiloHuang: 这样记忆体就是由 Python runtime 帮你管理 08/14 23:44
14F:→ dctzeng: 例如宣告1MB string 把位址当参数给dll当char* 处理好吗 08/14 23:44
15F:→ LiloHuang: 至於拷贝看是拷贝什麽,毕竟很多东西都得变 PyObject 08/14 23:44
16F:→ LiloHuang: 可以的呀,正常操作状况不会一直拷贝那 1MB 的 08/14 23:45
17F:→ dctzeng: 但其实string 不是char*,是硬碟任意资料 fd.Read() 来的 08/14 23:45
18F:→ dctzeng: 就是 fd.Read()读一坨资料; dll读一坨资料,两个相比而已 08/14 23:47
19F:→ LiloHuang: 你可以看看 byref, addressof, cast 这几个的用法 08/14 23:47
20F:→ LiloHuang: 资料从 Python 跟 C API 做交换,ctypes 会有一些成本 08/14 23:48
21F:→ dctzeng: 只是资料量大而且多thread要长时间跑,很不想额外memcpy 08/14 23:48
22F:→ LiloHuang: 当你东西是使用指标 (也就是我上面的范例) 算快的做法 08/14 23:48
23F:→ LiloHuang: 如果是我写我会尽量让 Python runtime 来帮我管记忆体 08/14 23:49
24F:→ LiloHuang: 当然还是得看场合,到底是谁该摆那一块记忆体... 08/14 23:51
25F:→ LiloHuang: 好比说用 create_string_buffer 来产生 buffer object 08/14 23:52
26F:→ dctzeng: 那1MB会重复一直读出来是因为那是dll的buffer,会重复更新 08/14 23:54
27F:推 LiloHuang: 不好意思我现在看到你修改後的文章了... 08/14 23:55
28F:→ dctzeng: 喔~ 不会 看到你提一些关键字没用过,google查一查 偷学 08/14 23:56
29F:推 LiloHuang: 那我重新修正,如果你只是想要比较用 c_char_p 就好 08/15 00:08
30F:→ LiloHuang: foo = 'x'*1024*1024*100 # 记忆体耗用 100 MB 左右 08/15 00:09
31F:→ LiloHuang: bar = c_char_p(foo) # 这个动作不会拷贝 100MB 08/15 00:09
32F:→ LiloHuang: ctypes.memmove(bar, "test", 4) # 硬是修改 foo 字串 08/15 00:09
33F:→ LiloHuang: # 雷同於你传入 DLL 08/15 00:10
34F:→ LiloHuang: print foo[0:10] # 顺便再印出 foo 的一部分观察 08/15 00:10
35F:→ LiloHuang: 以上的 foo 类似於你从 fd.read 读出的字串结果 08/15 00:11
36F:→ LiloHuang: ctypes.memmove 类似於你带入 DLL 的部分,试试看罗 08/15 00:12
37F:→ LiloHuang: 可搭配 ProcessExplorer 选 python.exe 观察记忆体用量 08/15 00:14
我试试 先谢谢
※ 编辑: dctzeng (111.243.146.150), 08/15/2014 00:23:42
38F:推 LiloHuang: 顺便回你文章的那个问题,那个写法应该也不会拷贝资料 08/15 00:41
39F:→ LiloHuang: 至於之所以会出错的原因是 from_address 是吃 integer 08/15 00:42
40F:→ LiloHuang: 用了 hex 就变成了字串,错误讯息是指参数型别不正确 08/15 00:43
41F:→ LiloHuang: 这种做法也是拿一个指标来操作的做法,都相当的快速 08/15 00:44
※ 编辑: dctzeng (111.243.146.150), 08/15/2014 01:06:02