这个结构对齐的原因是什么?

时间:2016-08-09 22:05:34

标签: c++ c struct memory-alignment struct-member-alignment

在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

在字段flagssurface之间存在8个字节的间隔,即使flags的基础类型为uint32_t。字段queueFamilyIndexCountpQueueFamilyIndices也是如此。为什么flagsqueueFamilyIndexCount占用8个字节,只有4个字节宽,而uint32_t类型的每个其他字段只占用4个字节?那些偏移的存储器对齐要求有什么特别之处吗?

2 个答案:

答案 0 :(得分:4)

VkSurfaceKHR是一个不可分派的句柄。根据Vulkan的定义,这是一个64位整数。因此它必须具有8字节对齐。

当布局结构时,编译器将确保每个成员获得该类型所需的对齐。如果surfaceflags之后立即出现,则不会有8字节对齐。因此,编译器在两者之​​间插入4个字节的填充。

答案 1 :(得分:1)

所有类型的大小均为sizeof(T),对齐要求为alignof(T)。它的实例总是需要在alignof(T)的多个地址的内存中布局。

在结构中,编译器会自动在元素之间插入 padding ,以便相对于结构的起始地址(即offsetof满足其所有元素的此要求。值)。这是后续struct元素之间的空白区域。

它还设置整个结构的alignof,以便其所有元素在内存中正确对齐。例如,在典型的64位平台上:

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

指针的大小为8字节(64位),并且对齐要求为8字节。在此结构中,cptr之间将有7个字节的填充,例如offsetof(A, c) == 0offsetof(A, ptr) == 8。并alignof(A) == 8。每当创建实例A a时(在堆栈上或堆上),&a % 8 == 0,以及&(a.ptr) % 8 == 0

这是因为一些CPU指令(例如SIMD向量指令)要求它们的操作数在字边界处对齐,即在存储器中的8的倍数(或32位的4)。如果没有正确的对齐方式,则无法直接使用这些指令,程序会变慢。

在此示例中,VkSurfaceKHRpQueueFamilyIndicesalignof == 8的指针。