В чем причина выравнивания этой структуры?

В шапке Вулкана vulkan.h есть структура, определенная как

typedef struct VkSwapchainCreateInfoKHR {
VkStructureType                  sType;
const void*                      pNext;
VkSwapchainCreateFlagsKHR        flags;
VkSurfaceKHR                     surface;
uint32_t                         minImageCount;
VkFormat                         imageFormat;
VkColorSpaceKHR                  imageColorSpace;
VkExtent2D                       imageExtent;
uint32_t                         imageArrayLayers;
VkImageUsageFlags                imageUsage;
VkSharingMode                    imageSharingMode;
uint32_t                         queueFamilyIndexCount;
const uint32_t*                  pQueueFamilyIndices;
VkSurfaceTransformFlagBitsKHR    preTransform;
VkCompositeAlphaFlagBitsKHR      compositeAlpha;
VkPresentModeKHR                 presentMode;
VkBool32                         clipped;
VkSwapchainKHR                   oldSwapchain;
} VkSwapchainCreateInfoKHR;

Я использовал следующий код, чтобы увидеть выравнивание каждого поля (Visual Studio 2015)

    std::cout <<
"sType: " << offsetof(VkSwapchainCreateInfoKHR, sType) << std::endl <<
"pNext: " << offsetof(VkSwapchainCreateInfoKHR, pNext) << std::endl <<
"flags: " << offsetof(VkSwapchainCreateInfoKHR, flags) << std::endl <<
"surface: " << offsetof(VkSwapchainCreateInfoKHR, surface) << std::endl <<
"minImageCount: " << offsetof(VkSwapchainCreateInfoKHR, minImageCount) << std::endl <<
"imageFormat: " << offsetof(VkSwapchainCreateInfoKHR, imageFormat) << std::endl <<
"imageColorSpace: " << offsetof(VkSwapchainCreateInfoKHR, imageColorSpace) << std::endl <<
"imageExtent: " << offsetof(VkSwapchainCreateInfoKHR, imageExtent) << std::endl <<
"imageArrayLayers: " << offsetof(VkSwapchainCreateInfoKHR, imageArrayLayers) << std::endl <<
"imageUsage: " << offsetof(VkSwapchainCreateInfoKHR, imageUsage) << std::endl <<
"imageSharingMode: " << offsetof(VkSwapchainCreateInfoKHR, imageSharingMode) << std::endl <<
"queueFamilyIndexCount: " << offsetof(VkSwapchainCreateInfoKHR, queueFamilyIndexCount) << std::endl <<
"pQueueFamilyIndices: " << offsetof(VkSwapchainCreateInfoKHR, pQueueFamilyIndices) << std::endl <<
"preTransform: " << offsetof(VkSwapchainCreateInfoKHR, preTransform) << std::endl <<
"compositeAlpha: " << offsetof(VkSwapchainCreateInfoKHR, compositeAlpha) << std::endl <<
"presentMode: " << offsetof(VkSwapchainCreateInfoKHR, presentMode) << std::endl <<
"clipped: " << offsetof(VkSwapchainCreateInfoKHR, clipped) << std::endl <<
"oldSwapchain: " << offsetof(VkSwapchainCreateInfoKHR, oldSwapchain) << std::endl <<
std::endl;

И получил эти результаты

sType: 0
pNext: 8
flags: 16
surface: 24
minImageCount: 32
imageFormat: 36
imageColorSpace: 40
imageExtent: 44
imageArrayLayers: 52
imageUsageFlags: 56
imageSharingMode: 60
queueFamilyIndexCount: 64
pQueueFamilyIndices: 72
preTransform: 80
compositeAlpha: 84
presentMode: 88
clipped: 92
oldSwapchain: 96

Между полями flags а также surface есть 8-байтный пробел, хотя flags имеет базовый тип uint32_t, То же самое относится и к полям queueFamilyIndexCount а также pQueueFamilyIndices, Почему flags а также queueFamilyIndexCount занимают 8 байтов, когда они имеют ширину всего 4 байта, и каждое другое поле типа uint32_t занимает всего 4 байта? Есть ли что-то особенное в требованиях к выравниванию памяти в этих смещениях?

2

Решение

VkSurfaceKHR это не отправляемая ручка. Который, по определениям Вулкана, является 64-битным целым числом. И поэтому он должен иметь 8-байтовое выравнивание.

Когда структуры размечаются, компилятор гарантирует, что каждый элемент получит выравнивание, которое требует тип. Если surface пришел сразу после flags, он не будет иметь 8-байтовое выравнивание. Таким образом, компилятор вставляет 4 байта заполнения между ними.

4

Другие решения

Все типы имеют размер sizeof(T)и требование выравнивания alignof(T), Его экземпляры всегда должны быть размещены в памяти по адресам, кратным alignof(T),

В структуре компилятор автоматически вставляет набивка между элементами, так что это требование выполняется для всех его элементов относительно начального адреса структуры (то есть для offsetof ценности). Это пустое пространство между последующими элементами структуры.

Это также устанавливает alignof всей структуры, так что все ее элементы будут правильно выровнены в памяти. Например, на типичной 64-битной платформе:

struct A {
char c;    // sizeof(char) == 1; alignof(char) == 1
int* ptr;  // sizeof(char) == 8; alignof(char) == 8
}

Указатели имеют размер 8 байт (64 бита), а также требование выравнивания 8 байт. В этой структуре будет 7 байтов заполнения c а также ptrтакой, что offsetof(A, c) == 0 а также offsetof(A, ptr) == 8, А также alignof(A) == 8, Всякий раз, когда экземпляр A a создается (в стеке или в куче), &a % 8 == 0, так что &(a.ptr) % 8 == 0,


Это сделано потому, что некоторые инструкции ЦП (например, векторные инструкции SIMD) требуют, чтобы их операнды были выровнены по границам слова, то есть кратны 8 (или 4 для 32-битных) в памяти. Без правильного выравнивания эти инструкции не могут быть использованы напрямую, и программа станет медленнее.


В этом примере VkSurfaceKHR а также pQueueFamilyIndices указатели с alignof == 8,

1

По вопросам рекламы [email protected]