为什么设置ctypes dll.function.restype = c_void_p返回长? [英] Why does setting ctypes dll.function.restype=c_void_p return long?

查看:169
本文介绍了为什么设置ctypes dll.function.restype = c_void_p返回长?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

奇怪的是,即使设置了 restype ,python也会返回 long ,而不是 c_void_p

It seems odd that even after setting restype, python returns long rather than c_void_p.

例如;

# python code
from ctypes import *
dll = windll.LoadLibrary("my.dll")
dll.my_object_create.restype = c_void_p
x = dll.my_object_create()
print type(x) # prints <type 'long'>

//c++ code
my_object *my_object_create() { return new my_object(); }
void my_object_destroy(my_object *obj) { delete obj; }

我最近不得不修复一个错误,该错误会给 x 返回另一个ctypes函数,指针被践踏。通过将初始dll调用更改为

I recently had to fix a bug where, feeding x back to another ctypes function, the pointer got trampled. This was fixed by changing the initial dll call to

x = c_void_p(dll.my_object_create())

...我猜想沿线某处的ctypes x

...I'm guessing somewhere along the line ctypes treated x as 4 bytes long not 8 (64 bit architecture).

所以我想知道是否有原因导致现有行为将您带入此陷阱?

So I am wondering if there is a reason why the existing behaviour leads you into this trap?

推荐答案

P_get 用于 P指针类型使用 PyLong_FromVoidPtr 。如果地址适合在平台 long 中,则返回Python int ;否则,它将返回精度为可变的Python long 。很好,但是当将此整数值作为参数传递时,默认行为是转换为C int ,在所有支持的平台上均为32位。

P_get for the 'P' pointer type uses PyLong_FromVoidPtr. If the address fits in a platform long, it returns a Python int; otherwise it returns a Python long, which has variable precision. That's fine, but when passing this integer value as an argument, the default behavior is to convert to a C int, which is 32-bit on all supported platforms.

我认为最好的解决方案是设置 argtypes 正确地将参数转换为指针类型。另一种选择是将 restype 设置为 c_void_p 的子类。使用子类会禁止转换为Python整数。 GetResult 通过调用 _ctypes_simple_instance ,实际上返回其名称和源注释所建议的相反。 (在2.5中,此函数名为 IsSimpleSubType ,然后源注释也是错误的,所讨论的简单绝不是元类 PyCSimpleType ,但基本类型为 _SimpleCData 。)

I think the best solution is to set argtypes to properly convert an argument to a pointer type. Another option is to set restype to a subclass of c_void_p. Using a subclass disables the conversion to a Python integer. GetResult checks this by calling _ctypes_simple_instance, which actually returns the opposite of what its name and the source comment suggest. (In 2.5 this function was named IsSimpleSubType, and the source comment was wrong back then too. The "simple" in question was never the metaclass PyCSimpleType, but the base type _SimpleCData.)

POSIX:

# Configure the interpreter to load visible extension-
# module symbols, such as _ctypes_simple_instance, 
# into the global symbol table.
import sys, DLFCN
sys.setdlopenflags((sys.getdlopenflags() & ~DLFCN.RTLD_LOCAL) |
                   DLFCN.RTLD_GLOBAL)
from ctypes import *

_ctypes_simple_instance = PyDLL(None)._ctypes_simple_instance
_ctypes_simple_instance.argtypes = py_object,
malloc = CDLL(None).malloc

class my_void_p(c_void_p): 
    pass



>>> _ctypes_simple_instance(c_void_p)
0
>>> _ctypes_simple_instance(my_void_p)
1

>>> malloc.restype = c_void_p
>>> type(malloc(100))
<type 'int'>
>>> malloc.restype = my_void_p
>>> type(malloc(100))
<class '__main__.my_void_p'>

Windows:

_ctypes_simple_instance

from ctypes import *

malloc = cdll.msvcrt.malloc

class my_void_p(c_void_p): 
    pass



>>> malloc.restype = c_void_p
>>> type(malloc(100))          
<class 'int'>
>>> malloc.restype = my_void_p
>>> type(malloc(100))         
<class '__main__.my_void_p'>

这篇关于为什么设置ctypes dll.function.restype = c_void_p返回长?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆