[问题] 请教处理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