6

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())

...私は、ctypesxが 8 ではなく 4 バイト長 (64 ビット アーキテクチャ) として扱われる行のどこかを推測しています。

それで、既存の行動があなたをこの罠に導く理由があるのだろうかと思いますか?

4

1 に答える 1

8

P_get'P' ポインター タイプの場合は を使用しPyLong_FromVoidPtrます。アドレスがプラットフォームに適合する場合、longPython を返しますintlongそれ以外の場合は、変数の精度を持つPython を返します。それは問題ありませんが、この整数値を引数として渡す場合、デフォルトの動作は、サポートされているすべてのプラットフォームで 32 ビットである C に変換することです。int

argtypes最善の解決策は、引数をポインター型に適切に変換するように設定することだと思います。別のオプションはrestype、 のサブクラスに設定することですc_void_p。サブクラスを使用すると、Python 整数への変換が無効になります。GetResultを呼び出してこれをチェックし_ctypes_simple_instanceます。実際には、その名前とソース コメントが示唆するものとは反対の結果を返します。(2.5IsSimpleSubTypeでは、この関数は という名前でしたが、当時はソース コメントも間違っていました。問題の「単純」は決して metaclassPyCSimpleTypeではなく、基本型_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'>

ウィンドウズ:

_ctypes_simple_instance_ctypes.pyd によってエクスポートされません。

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'>
于 2013-07-24T17:24:54.893 に答える