为什么设置ctypes dll.function.restype = c_void_p返回多长时间?

时间:2013-07-24 16:47:22

标签: python ctypes

即使在设置restype之后,python仍然返回long而不是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调用更改为

来解决此问题
x = c_void_p(dll.my_object_create())

...我猜测ctypes处理x的某个地方长4个字节而不是8个(64位架构)。

所以我想知道现有行为是否导致你进入这个陷阱?

1 个答案:

答案 0 :(得分:7)

P_get使用'P' pointer type

PyLong_FromVoidPtr。如果地址适合平台long,则返回Python int;否则它返回一个Python long,它具有可变精度。这很好,但是当将此整数值作为参数传递时,默认行为是convert to a C int,在所有支持的平台上都是32位。

我认为最好的解决方案是设置argtypes以正确地将参数转换为指针类型。另一种选择是将restype设置为c_void_p的子类。使用子类禁用转换为Python整数。 GetResult通过调用_ctypes_simple_instance来检查这一点,IsSimpleSubType实际上返回与其名称和源注释建议相反的内容。 (在2.5中,这个函数被命名为PyCSimpleType,而源注释也是错误的。所讨论的“简单”从不是元类_SimpleCData,而是基类型{{3}}。)

<强> 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'>

<强>窗:

_ctypes.pyd不会导出

_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'>