python - 区分“基本” ctypes 数据类型及其子类?
问题描述
介绍
我正在开发一个代码生成器,它将围绕ctypes.cdll
加载的函数生成函数。生成器将获取有关ctypes
参数和返回值的信息,并生成行为(并且在某种程度上看起来)如下所示的内容:
func = getattr(dll, 'UglyLongAndUselessCName')
func.argtypes = [ctypes.c_uint32, ctypes.c_int8, ctypes.c_char_p]
func.restype = ctypes.c_int16
def nice_python_name(handle: int, arg1: int, arg2: str) -> int:
return func(handle, arg1, arg2)
请注意 python 类型注释如何与ctypes
函数参数的数据类型很好地配合使用。nice_python_name
另请注意,函数和函数中的python类型之间没有转换代码func
。这就是我的问题所在。
接近问题
ctypes
文档说,如果加载的 DLL 函数的属性argtypes
是使用“基本数据类型”指定的,那么在调用加载的 DLL 函数时,ctypes
将为您转换为 python 类型。这很好,因为在这种情况下,我生成的代码将类似于上面的示例 - 对于返回值,我不需要显式地将ctypes
对象转换为 python 类型的值,而对于参数则相反。
但是,文档还说,对于“基本数据类型的子类”,这个技巧将不起作用,调用加载的 DLL 函数将需要ctypes
对象作为参数,结果将是一个ctypes
对象。
这是有关它的ctypes
文档的摘录:
基本数据类型,当作为外部函数调用结果返回时,或者,例如,通过检索结构字段成员或数组项时,会透明地转换为本机 Python 类型。换句话说,如果外部函数具有
restype
ofc_char_p
,您将始终收到 Python 字节对象,而不是c_char_p
实例。基本数据类型的子类不继承此行为。因此,如果外部函数
restype
是 的子类c_void_p
,您将从函数调用中收到该子类的实例。当然,你可以通过访问 value 属性来获取指针的值。
所以,我想解决这个问题。
似乎我需要知道一个类型是“基本”还是“子类”。这将帮助我定义生成代码的方式,即对于“基本”类型,生成的代码看起来与上面的示例相似,而对于“基本”类型的子类,它将具有从ctypes
对象到合理 python 类型的额外转换(或者生成器只会抛出一个异常说“不支持”)。
问题:
如何区分“基本ctypes
数据类型”和“基本ctypes
数据类型的子类”?
我查看了ctypes
python 模块的代码,发现c_void_p
和c_char_p
都是 的子类ctypes._SimpleCData
,因此其中一个无论如何都不是另一个的子类。
另外,我是否误解了这个问题也适用于输入参数,或者这只是返回值的处理?
解决方案
...我是否误解了这个问题也适用于输入参数,或者这只是返回值的处理?
它不适用于输入参数,如下面的序列所示:
>>> dll=CDLL('msvcrt')
>>> dll.printf.argtypes = c_char_p,
>>> dll.printf(b'abc') # Note: 3 is the return value of printf
abc3
>>> class LPCSTR(c_char_p): # define a subtype
... pass
...
>>> dll.printf.argtypes = LPCSTR,
>>> dll.printf(b'abc')
abc3
转换仍然适用于输入子类型;但是,输出子类型的工作方式与您的文档引用提到的不同:
>>> dll.ctime.argtypes = c_void_p,
>>> dll.ctime.restype = c_char_p
>>> dll.ctime(byref(c_int(5)))
b'Wed Dec 31 16:00:05 1969\n'
>>> dll.ctime.restype = LPCSTR
>>> dll.ctime(byref(c_int(5))) # not converted to Python byte string
LPCSTR(1989707373328)
>>> x = dll.ctime(byref(c_int(5))) # but can get the value
>>> x.value
b'Wed Dec 31 16:00:05 1969\n'
推荐阅读
- java - 如何检查为什么 JVM 无法终止
- html - Giving different wallpapers to a page
- elasticsearch - Elasticsearch delete_by_query 版本冲突
- ios - 构建 XCTest UI 测试套件的最佳实践是什么?
- r - Return value between two characters in a string
- css - 当flexbox旁边的div宽度增加时,如何避免flexbox中的项目不从div中出来?
- html - 我正在用 HTML 和 CSS 制作一个圆环图,需要帮助将我的跨度放在楔子的中间
- regex - 正则表达式查找单个数字的单词
- vue.js - Vue.js 在输入中选择的值不匹配:selected 参数
- css - svg 不会缩放到全高,父 flex,flex-direction:列