ctypes将c_uint64转换为c_char_p

2024-05-16 00:01:12 发布

您现在位置:Python中文网/ 问答频道 /正文

from ctypes import *

In [27]: sizeof(c_char_p)
Out[27]: 8

In [28]: sizeof(c_uint64)
Out[28]: 8

In [29]: cast(c_uint64(0), c_char_p)
---------------------------------------------------------------------------
ArgumentError                             Traceback (most recent call last)

/Users/az/Programmierung/PyCPython/<ipython console> in <module>()

/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/ctypes/__init__.pyc in cast(obj, typ)
    479 _cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr)
    480 def cast(obj, typ):
--> 481     return _cast(obj, obj, typ)
    482 
    483 _string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)

ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong type

为什么cast失败?

如果sizeof两种类型都是相同的,ctypes.cast总是可以工作的,有什么替代方法吗?


Tags: inpyobjobjectoutctypescharcast
3条回答

CU uint64是内存地址吗?如果是,则可以执行以下操作:

>>> n = c_uint64(1234567890) #assume this is a valid memory address...beware of segfaults
>>> p = c_char_p(n.value)
>>> #or..
>>> p.value = n.value #special semantics for c_char_p - accepts both addresses and strings

(见http://docs.python.org/library/ctypes.html#ctypes.c_char_p

或者,如果您要做的是将存储在c_uint64中的值重新解释为以空结尾的8字节字符缓冲区,则需要将指向c_uint64的指针转换为c_char_p。。。

>>> n = c_uint64(ord("A"))
>>> n
c_ulong(65L)
>>> p = cast(pointer(n), c_char_p)
>>> p
c_char_p(47101614291216)
>>> p.value
'A'

如果不是以空结尾,则ctypes将防止缓冲区溢出:

>>> n2 = c_uint64(0xFFFFFFFFFFFFFFFF)
>>> p2 = cast(pointer(n2), c_char_p)
>>> p2.value[0]
'\xff'
>>> p2.value
'\xff\xff\xff\xff\xff\xff\xff\xff'
>>> p2.value[9]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

针对艾伯特的评论进行更新:

I want to know why cast doesn't work here

原因的答案在文档和代码中-http://docs.python.org/library/ctypes.html#ctypes.cast

ctypes.cast(obj, type) This function is similar to the cast operator in C. It returns a new instance of type which points to the same memory block as obj. type must be a pointer type, and obj must be an object that can be interpreted as a pointer.

合同在code中强制执行:

_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr)
def cast(obj, typ):
    return _cast(obj, obj, typ)

因此,要转换的第一个参数(对象)必须可转换为c_void_p。在source中,从_param()签出c_void_p_。这是转换为c_void_p的地方。有Python整数、Python字符串、Python unicode字符串、c_void_p、ctypes数组/指针、byref结果、函数指针、c_char_p/c_wchar_p以及定义了_as_parameter_()方法的任何对象的转换器。

没有ctypes整数对象的转换器。我只看2.6代码(因为这是您正在使用的代码),所以在2.7或3.x中可能不是这样

至于理由——这个问题必须向开发人员提出。

...if there is a generic version which always works (for all cases, not just c_char_p).

据我所知,解决方案正如我在第一个例子中所展示的那样。使用Python整数构造指针对象的值成员或将其赋值给指针对象的值成员(转换器知道如何从Python整数转换)。cast()将不起作用,因为它就是这样实现的。

我现在往这边走:

def isPointerType(t):
    if issubclass(t, _ctypes._Pointer): return True
    return False

def getValueOf(obj):
    if isPointerType(obj.__class__):
        return cast(obj, c_void_p).value
    else:
        return obj.value

def static_cast(obj, t):
    newObj = t()
    if isPointerType(t):
        cast(pointer(obj), POINTER(c_void_p)).contents.value = getValueOf(obj)
    else:
        newObj.value = getValueOf(obj)
    return newObj

看起来有点复杂,但我还没有找到一个更简单的方法。

您必须获得指向该值的指针,请检查:

In [29]: i = c_uint32(0x30313233)

In [30]: cast(pointer(i), c_char_p).value
Out[30]: '3210'

相关问题 更多 >