使用ctypes处理128位整数

10

如何使用 Python ctypes 支持 128 位整数(目前的 __uint128_t)?

也许可以使用两个 uint64_t 的用户自定义结构体,但这将在需要对齐时创建对齐问题。

有没有关于为什么 ctypes 没有扩展支持 128 位整数的想法?


一个紧凑的结构体(pack = 1)至少可以解决对齐问题。 - epx
不是真的,为了获得最佳性能,这些向量需要在内存中保持16字节对齐。 - Fil
2
注意:__uint128_t 似乎是 GCC 的一个扩展:https://dev59.com/xmMl5IYBdhLWcg3wR1SD#18531871 - iljau
在从ctypes.Structure派生的结构中,有一个名为_pack_的魔法属性,但是值16似乎并没有被采用,至少ctypes.alignment()仍然报告8 - Dima Tisnek
1个回答

2
如果您确实需要使用128位的整数,那么就不用担心对齐问题。目前没有任何架构或机器支持128位本地整数算术运算,因此也不会有机器需要或受益于16字节对齐的128位整数。只需使用用户定义的结构即可。
如果您真正需要的是128位向量类型的支持,那么您可能需要对它们进行对齐。也就是说,如果您在Python代码中创建这些向量并通过引用将它们传递给C/C++代码,则需要对它们进行对齐。如果在堆栈上正确对齐(如果架构ABI要求)这些向量,则无法可靠地按值传递它们,也不存在获取ctypes在堆栈上正确对齐它们的方法。从C/C++传递到Python的向量应该已经适当地对齐。因此,如果您可以安排所有向量都在C/C++代码中分配,那么使用用户定义的结构也是可以的。
假设您确实需要在Python代码中创建对齐的向量,那么我已经包含了用于对齐的ctypes数组代码。我还有其他ctypes类型的对齐代码,但没有包含在代码中以保持代码大小。数组应该足够满足大多数需求。这些对齐数组有一些限制。如果通过值传递它们到C/C++函数或将它们包含为结构或联合的成员,它们将无法正确对齐。您可以使用“*”运算符创建对齐的数组的对齐的数组。
使用“aligned_array_type(ctypes-type, length, alignment)”创建新的对齐数组类型。“aligned_type(ctypes-type, alignment)”用于创建已经存在的数组类型的对齐版本。
import ctypes

ArrayType = type(ctypes.Array)

class _aligned_array_type(ArrayType):
    def __mul__(self, length):
        return aligned_array_type(self._type_ * self._length_,
                      length, self._alignment_)

    def __init__(self, name, bases, d):
        self._alignment_ = max(getattr(self, "_alignment_", 1), 
                       ctypes.alignment(self))

def _aligned__new__(cls):
    a = cls._baseclass_.__new__(cls)
    align = cls._alignment_
    if ctypes.addressof(a) % align == 0:
        return a
    cls._baseclass_.__init__(a) # dunno if necessary
    ctypes.resize(a, ctypes.sizeof(a) + align - 1)
    addr = ctypes.addressof(a)
    aligned = (addr + align - 1) // align * align
    return cls.from_buffer(a, aligned - addr)

class aligned_base(object):
    @classmethod
    def from_address(cls, addr):
        if addr % cls._alignment_ != 0:
            raise ValueError, ("address must be %d byte aligned"
                       % cls._alignment_)
        return cls._baseclass_.from_address(cls, addr)

    @classmethod
    def from_param(cls, addr):
        raise ValueError, ("%s objects may not be passed by value"
                   % cls.__name__)

class aligned_array(ctypes.Array, aligned_base):
    _baseclass_ = ctypes.Array
    _type_ = ctypes.c_byte
    _length_ = 1
    __new__ = _aligned__new__

_aligned_type_cache = {}

def aligned_array_type(typ, length, alignment = None):
    """Create a ctypes array type with an alignment greater than natural"""

    natural = ctypes.alignment(typ)
    if alignment == None:
        alignment = typ._alignment_
    else:
        alignment = max(alignment, getattr(typ, "_alignment_", 1))

    if natural % alignment == 0:
        return typ * length
    eltsize = ctypes.sizeof(typ)
    eltalign = getattr(typ, "_alignment_", 1)
    if eltsize % eltalign != 0:
        raise TypeError("type %s can't have element alignment %d"
                " in an array" % (typ.__name__, alignment))
    key = (_aligned_array_type, (typ, length), alignment)
    ret = _aligned_type_cache.get(key)
    if ret == None:
        name = "%s_array_%d_aligned_%d" % (typ.__name__, length,
                           alignment)
        d = {"_type_": typ,
             "_length_": length,
             "_alignment_": alignment}
        ret = _aligned_array_type(name, (aligned_array,), d)
        _aligned_type_cache[key] = ret
    return ret

def aligned_type(typ, alignment):
    """Create a ctypes type with an alignment greater than natural"""

    if ctypes.alignment(typ) % alignment == 0:
        return typ
    if issubclass(typ, ctypes.Array):
        return aligned_array_type(typ._type_, typ._length_,
                      alignment)
    else:
        raise TypeError("unsupported type %s" % typ)

@ReubenThomas,你的编译器可能会给那个类型分配对齐,但这不是出于性能或正确性方面的必要。 - Ross Ridge
@ReubenThomas 我建议您发布一个新问题,详细说明您的问题,我相信有人可以解释实际发生的情况。您需要将问题简化为 [mcve] 并根据调试问题的要求在问题中包含它。 - Ross Ridge
__int128 在某些平台上确实是16字节对齐的,如 https://stackoverflow.com/q/52531695/569229 中所讨论的。具体来说,GCC可以为它们生成代码,假设16字节对齐。 - Reuben Thomas
你提到你有其他ctypes类型的代码:如果你有Structure的话,我很想看看它! - Reuben Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接