Vulkan 和结构成员对齐
Vulkan and struct member alignment
Vulkan 在其函数中广泛使用结构来传递大量参数,并通过使用结构类型和 "next" 指针作为每个结构。例如,取这个函数:
VkResult vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
VkInstanceCreateInfo
的描述:
typedef struct VkInstanceCreateInfo {
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
让我感兴趣的是,据我所知,结构成员的打包由编译器决定(除了顺序,它不是)。据我所知,这与没有 compiler-dependent 问题的 COM-based API 形成对比。我一直在查看 Vulkan headers,希望找到 compiler-specific 对齐方式 pragmas/statements,但没有什么突出的。
查看 data structure alignment Wikipedia page 之类的页面表明常见的 well-known 编译器遵循 x86 上的特定规则:
The type of each member of the structure usually has a default
alignment, meaning that it will, unless otherwise requested by the
programmer, be aligned on a pre-determined boundary. The following
typical alignments are valid for compilers from Microsoft (Visual
C++), Borland/CodeGear (C++Builder), Digital Mars (DMC), and GNU (GCC)
when compiling for 32-bit x86...
但是使用像 "usually" 和 "typical" 这样的狡猾的词让我觉得它不可靠。 this SO answer 中的一段更引人注目:
IMPORTANT NOTE: Both the C and C++ standards state that structure
alignment is implementation-defined. Therefore each compiler may
choose to align data differently, resulting in different and
incompatible data layouts. For this reason, when dealing with
libraries that will be used by different compilers, it is important to
understand how the compilers align data. Some compilers have
command-line settings and/or special #pragma statements to change the
structure alignment settings.
如果我使用由一个编译器使用一组规则编译的 Vulkan SDK,并且我正在使用另一个编译器编写客户端应用程序,是否存在对齐问题的可能性?我在这里错过了什么?
If I'm using the Vulkan SDK compiled by one compiler with one set of rules, and I'm writing a client application using another compiler, isn't there the potential for alignment problems?
我可以编写一个由 GCC 编译的程序,该程序链接(动态或以其他方式)由 Clang 编译的程序。或者在它支持的平台上 Visual Studio。或任何其他编译器。从我的编译器中,我可以调用将各种结构传递给在目标编译器下编译的代码的函数。
并且有效。为什么?
因为在这些 libraries/SO/DLL/executables 的边界发生的行为不是由编译器定义的;它由 平台 定义。库间通信受该平台上所有编译器同意的通信协议的约束。这就是您如何对甚至可能尚未编译的代码进行 OS 系统调用。这是因为源和目标已经就调用约定和应用程序二进制接口 (ABI) 达成一致。
系统的 ABI 定义了结构布局的外观。如果编译器正在编译试图跨 ABI 边界传递结构的代码,则编译器必须确保它生成的代码的结构布局符合 ABI。对于编译器确定不会跨越 ABI 边界的类型,它可以做任何它想做的事情,但一般来说,它仍然会使用 ABI 的约定。
Linux 系统使用 Itanium ABI。 Windows 有自己的 ABI。每个平台都有一个 ABI,这是编译到该平台的编译器所符合的。
因此,唯一可能出现布局问题的情况是,如果您将这些结构发送到另一个 操作系统。考虑到 Vulkan 是一个低级 API,这可能不是一个好主意。并且肯定不是 Vulkan 的预期用例。
Vulkan 在其函数中广泛使用结构来传递大量参数,并通过使用结构类型和 "next" 指针作为每个结构。例如,取这个函数:
VkResult vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
VkInstanceCreateInfo
的描述:
typedef struct VkInstanceCreateInfo {
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
让我感兴趣的是,据我所知,结构成员的打包由编译器决定(除了顺序,它不是)。据我所知,这与没有 compiler-dependent 问题的 COM-based API 形成对比。我一直在查看 Vulkan headers,希望找到 compiler-specific 对齐方式 pragmas/statements,但没有什么突出的。
查看 data structure alignment Wikipedia page 之类的页面表明常见的 well-known 编译器遵循 x86 上的特定规则:
The type of each member of the structure usually has a default alignment, meaning that it will, unless otherwise requested by the programmer, be aligned on a pre-determined boundary. The following typical alignments are valid for compilers from Microsoft (Visual C++), Borland/CodeGear (C++Builder), Digital Mars (DMC), and GNU (GCC) when compiling for 32-bit x86...
但是使用像 "usually" 和 "typical" 这样的狡猾的词让我觉得它不可靠。 this SO answer 中的一段更引人注目:
IMPORTANT NOTE: Both the C and C++ standards state that structure alignment is implementation-defined. Therefore each compiler may choose to align data differently, resulting in different and incompatible data layouts. For this reason, when dealing with libraries that will be used by different compilers, it is important to understand how the compilers align data. Some compilers have command-line settings and/or special #pragma statements to change the structure alignment settings.
如果我使用由一个编译器使用一组规则编译的 Vulkan SDK,并且我正在使用另一个编译器编写客户端应用程序,是否存在对齐问题的可能性?我在这里错过了什么?
If I'm using the Vulkan SDK compiled by one compiler with one set of rules, and I'm writing a client application using another compiler, isn't there the potential for alignment problems?
我可以编写一个由 GCC 编译的程序,该程序链接(动态或以其他方式)由 Clang 编译的程序。或者在它支持的平台上 Visual Studio。或任何其他编译器。从我的编译器中,我可以调用将各种结构传递给在目标编译器下编译的代码的函数。
并且有效。为什么?
因为在这些 libraries/SO/DLL/executables 的边界发生的行为不是由编译器定义的;它由 平台 定义。库间通信受该平台上所有编译器同意的通信协议的约束。这就是您如何对甚至可能尚未编译的代码进行 OS 系统调用。这是因为源和目标已经就调用约定和应用程序二进制接口 (ABI) 达成一致。
系统的 ABI 定义了结构布局的外观。如果编译器正在编译试图跨 ABI 边界传递结构的代码,则编译器必须确保它生成的代码的结构布局符合 ABI。对于编译器确定不会跨越 ABI 边界的类型,它可以做任何它想做的事情,但一般来说,它仍然会使用 ABI 的约定。
Linux 系统使用 Itanium ABI。 Windows 有自己的 ABI。每个平台都有一个 ABI,这是编译到该平台的编译器所符合的。
因此,唯一可能出现布局问题的情况是,如果您将这些结构发送到另一个 操作系统。考虑到 Vulkan 是一个低级 API,这可能不是一个好主意。并且肯定不是 Vulkan 的预期用例。