快速结构外部填充



所以我在 swift 中有以下结构

typealias float = Float32
typealias Point = float2
typealias Int = UInt32
//This is a struct that is meant to be the elements in an array that is immensly acessable to c
//CAREFUL this is LIKELY mirrored in a different thing
public struct Info {
var position:Point = Point(x: 0, y: 0)
var strength:float = 1
var altitude:float = 3.141592 / 2.0
var azmuth:Point = Point(x: 0, y: 0)
var state:Int = 0
}

此结构存储在分配有Array(repeating: ...的数组中

每一帧我都会将一个指针传递到该数组中,进入我的 c++ 代码,我在这里有一个镜像结构

struct Info {
float positionX;
float positionY;
float strength;
float altitude;
float azmuthX;
float azmuthY;
int state;
float pad; //WHy???
}; 

现在注意它在那里的额外浮点"pad",因为当我去读取第一个元素以外的元素时,结构声明中没有它,数据被一个浮点数的大小偏移(事情会移动一个字段)。

为什么 c++ 结构上的 pad 字段是必需的?Swift 中额外的浮点数或额外填充的原因是什么?

float2是 C 类型simd_float2的 Swift 映射,即 在<simd/vector_types.h中定义为

/*! @abstract A vector of two 32-bit floating-point numbers.
*  @description In C++ and Metal, this type is also available as
*  simd::float2. The alignment of this type is greater than the alignment
*  of float; if you need to operate on data buffers that may not be
*  suitably aligned, you should access them using simd_packed_float2
*  instead.                                                                  */
typedef __attribute__((__ext_vector_type__(2))) float simd_float2;

关键点是

此类型的对齐大于浮点的对齐

你可以用

print(MemoryLayout<float>.alignment)  // 4
print(MemoryLayout<float2>.alignment) // 8

这会导致 Swift 类型的对齐Info8,以及它的步幅(即偏移量 存储在数组中的连续Info元素之间的字节数)为 32。

print(MemoryLayout<Info>.alignment) // 8
print(MemoryLayout<Info>.stride)    // 32

另一方面,C型struct Info只有floatint成员,它们都具有 4 个字节的对齐方式。没有 最后一个float pad;成员,数组中此类型的连续元素之间的偏移量为 28 个字节,而不是 32 个字节。

这就解释了其中的区别。你真正应该做的是定义 仅 C 中的类型,并将该定义导入到 Swift 中。这是 保证保留内存布局的唯一方法, 正如苹果公司的乔·格罗夫(Joe Groff)在 将 C 语义映射到 Swift:

如果你依赖于特定的布局,你应该在 C 中定义结构,并暂时将其导入到 Swift 中。

最新更新