Внешнее заполнение структуры Swift

avatar
J.Doe
8 апреля 2018 в 09:46
503
1
2

Итак, у меня есть следующая структура в 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++? Что такое дополнительное поплавок или причина дополнительного заполнения в Swift?

Источник
Martin R
8 апреля 2018 в 10:03
1

typealias Int = UInt32 — плохая идея, потому что он затеняет встроенный тип Int.

Ответы (1)

avatar
Martin R
8 апреля 2018 в 10:39
2

float2 — это отображение Swift типа C simd_float2, которое определено в <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;

Ключевым моментом является

Выравнивание этого типа больше, чем выравнивание float

и вы можете проверить это с помощью

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

Это приводит к тому, что выравнивание типа Swift Info равно 8, а его шаг (т. е. смещение в байтах между смежными элементами Info при сохранении в массиве) равно 32.

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

С другой стороны, тип C struct Info имеет только float и int члены, все из которых имеют выравнивание по 4 байта. Без final float pad;, смещение между смежными элементами этого типа в массиве составляет 28 байт, а не 32.

Это объясняет разницу. Что вы на самом деле должны сделать, так это определить тип только на C и импортировать это определение в Swift. Это единственный способ, который гарантированно сохранит макет памяти, как пишет Джо Грофф из Apple в Отображение семантики C в Swift:

Если вы зависите от определенного макета, вы должны определить структуру на C и пока импортировать ее в Swift.