2016-08-09 11 views
2

В Vulkan заголовке 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-байтовый зазор, накануне n, хотя flags имеет базовый тип uint32_t. То же самое относится к полям queueFamilyIndexCount и pQueueFamilyIndices. Почему flags и queueFamilyIndexCount занимают 8 байтов, когда они всего 4 байта, а каждое другое поле типа uint32_t занимает всего 4 байта? Есть ли что-то особенное в отношении требований к выравниванию памяти в этих смещениях?

+2

Прокладка ......................... –

+0

Но почему только поля заполняются? Оба они смещены на несколько из 16, поэтому почему следующее поле должно заполнить? – rhynodegreat

+2

@ πάνταῥεῖ Он, милый. :) –

ответ

4

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

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

+0

Проблема в том, что 'flags' занимает 8 байтов. – rhynodegreat

+6

@rhynodegreat: Нет, это не так. Он занимает 4 байта. После него четыре * неиспользуемых байта *, так что следующее поле может быть выровнено по 8 байт. –

+1

Ах, поэтому добавление добавляется, потому что следующее поле имеет 8 байтов и должно быть выровнено. То же самое с 'queueFamilyIndexCount', за которым следует указатель. – rhynodegreat

1

Все типы имеют размер 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.

+0

Вы можете использовать пустое пространство – Tibrogargan

 Смежные вопросы

  • Нет связанных вопросов^_^