Python ctypes对齐数据结构
Python ctypes align data structure
我有一个编译为共享对象的 C 库,我想围绕它构建一个 ctypes 接口以从 Python 调用 C 函数。
一般来说它工作正常,但在 C 库中有一个双精度数组的定义:
typedef double __attribute__ ((aligned (32))) double_array[512];
我发现没有办法直接访问这个类型,所以我在Python中定义:
DoubleArray = ctypes.c_double * 512
虽然这在大多数情况下都可行,但有时 C 库会出现段错误,我猜这是因为 DoubleArray
未对齐到 32 字节(也许库期望这样做,因为数据已传递给 AVX)。
我该如何解决这个问题?
数组最多不对齐 31 个字节。要获得对齐的数组,请过度分配 31 个字节,然后,如果基地址未对齐,请添加一个偏移量以使其对齐。这是一个通用函数:
def aligned_array(alignment, dtype, n):
mask = alignment - 1
if alignment == 0 or alignment & mask != 0:
raise ValueError('alignment is not a power of 2')
size = n * ctypes.sizeof(dtype) + mask
buf = (ctypes.c_char * size)()
misalignment = ctypes.addressof(buf) & mask
if misalignment:
offset = alignment - misalignment
else:
offset = 0
return (dtype * n).from_buffer(buf, offset)
例如:
>>> arr = aligned_array(2**4, ctypes.c_double, 512)
>>> hex(ctypes.addressof(arr))
'0x1754410'
>>> arr = aligned_array(2**8, ctypes.c_double, 512)
>>> hex(ctypes.addressof(arr))
'0x1755500'
>>> arr = aligned_array(2**12, ctypes.c_double, 512)
>>> hex(ctypes.addressof(arr))
'0x1757000'
>>> arr = aligned_array(2**16, ctypes.c_double, 512)
>>> hex(ctypes.addressof(arr))
'0x1760000'
我有一个编译为共享对象的 C 库,我想围绕它构建一个 ctypes 接口以从 Python 调用 C 函数。
一般来说它工作正常,但在 C 库中有一个双精度数组的定义:
typedef double __attribute__ ((aligned (32))) double_array[512];
我发现没有办法直接访问这个类型,所以我在Python中定义:
DoubleArray = ctypes.c_double * 512
虽然这在大多数情况下都可行,但有时 C 库会出现段错误,我猜这是因为 DoubleArray
未对齐到 32 字节(也许库期望这样做,因为数据已传递给 AVX)。
我该如何解决这个问题?
数组最多不对齐 31 个字节。要获得对齐的数组,请过度分配 31 个字节,然后,如果基地址未对齐,请添加一个偏移量以使其对齐。这是一个通用函数:
def aligned_array(alignment, dtype, n):
mask = alignment - 1
if alignment == 0 or alignment & mask != 0:
raise ValueError('alignment is not a power of 2')
size = n * ctypes.sizeof(dtype) + mask
buf = (ctypes.c_char * size)()
misalignment = ctypes.addressof(buf) & mask
if misalignment:
offset = alignment - misalignment
else:
offset = 0
return (dtype * n).from_buffer(buf, offset)
例如:
>>> arr = aligned_array(2**4, ctypes.c_double, 512)
>>> hex(ctypes.addressof(arr))
'0x1754410'
>>> arr = aligned_array(2**8, ctypes.c_double, 512)
>>> hex(ctypes.addressof(arr))
'0x1755500'
>>> arr = aligned_array(2**12, ctypes.c_double, 512)
>>> hex(ctypes.addressof(arr))
'0x1757000'
>>> arr = aligned_array(2**16, ctypes.c_double, 512)
>>> hex(ctypes.addressof(arr))
'0x1760000'