用Python ctypes支持128位整數(當前是__uint128_t)的最佳方式是什麼?用ctypes處理128位整數
也許是兩個uint64_t的用戶定義的結構,但這會在需要時創建對齊問題。
爲什麼ctypes沒有擴展到支持128位整數的任何想法?
用Python ctypes支持128位整數(當前是__uint128_t)的最佳方式是什麼?用ctypes處理128位整數
也許是兩個uint64_t的用戶定義的結構,但這會在需要時創建對齊問題。
爲什麼ctypes沒有擴展到支持128位整數的任何想法?
如果你真的想與128位整數一起工作,那麼你不必擔心對齊。沒有當前的體系結構,沒有任何Python運行的機器支持128位本地整數算術。所以沒有機器需要16字節對齊的128位整數。只需使用該用戶定義的結構,你就會好起來的。
如果你真正要求的是支持128位矢量類型,那麼你可能需要讓它們對齊。也就是說,如果您使用Python代碼創建並通過引用C/C++代碼傳遞它們,則需要它們對齊。你無法可靠地通過它們傳遞它們,沒有辦法讓ctypes在堆棧上正確地對齊它們(如果ABI體系結構要求的話)。從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)
打包結構(_pack_ = 1)至少可以解決對齊問題。 – epx
並非如此,爲了獲得最佳性能,需要將這些向量保存在與16字節對齊的內存中。 – Fil
注意:'__uint128_t'似乎是一個GCC擴展:http://stackoverflow.com/a/18531871/2419207 – iljau