为什么某些结构类型让我们设置只能是特定值的成员?

Why do some struct types let us set members that can only be a certain value?

我正在阅读一些 vulkan 结构类型,这是众多示例之一,但我将使用的是 vkInstanceCreateInfo。文档指出:

The VkInstanceCreateInfo structure is defined as:

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;
} VkInstanceCreateInfo;

然后在下面的选项中我们看到:

sType is the type of this structure

sType must be VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO

如果我们无论如何都没有任何选项,为什么这个参数不只是在创建类型时隐式设置?

注意:我意识到这不是 vulkan 特有的东西 API。

更新:我不只是专门谈论 vulkan,而是所有只能是特定类型的参数。

该设计允许将结构链接在一起,以便扩展可以为现有调用创建额外的参数,而不会干扰原始 API 结构并且不会相互干扰。

几乎 Vulkan 中的每个 结构都有 sType 作为它的第一个成员,pNext 作为它的第二个成员。这意味着如果你有一个 void* 并且你所知道的是它是某种 Vulkan API 结构,你可以安全地读取前 32 位并且它将是一个 VkStructureType 并且读取接下来的 32 位或 64 位,它会告诉您链中是否有另一个结构。

例如,有一个用于分配内存的 VkMemoryAllocateInfo 结构(除了 sTypepNext 分配的大小和它应该来自的堆索引。但是如果我想使用 "dedicated allocation" 扩展怎么办。那么我还需要用额外的信息填充一个 VkMemoryDedicatedAllocateInfo 结构。但是我仍然需要调用相同的 vkAllocateMemory 函数,它只需要一个VkMemoryAllocateInfo...那么我填写的VkMemoryDedicatedAllocateInfo结构放在哪里呢?我在VkMemoryAllocateInfopNext字段中放了一个指向它的指针。

也许我还想与一些 OpenGL 代码共享此内存。有一个扩展可以让你这样做,但你需要填写一个 VkExportMemoryAllocateInfo 结构并在分配期间将其传递进来。好吧,我可以通过将它放在我的 VkMemoryDedicatedAllocateInfo 结构的 pNext 字段中来做到这一点。只要我愿意,我就可以创建一连串这样的结构。

这是真正重要的部分。由于所有结构都将 sType 作为它们的第一个字段,因此扩展可以沿着这个结构链导航并找到它关心的结构,而无需了解除了它们总是以 sTypepNext.

所有这些意味着 Vulkan 可以通过改变现有函数行为的方式进行扩展,但不会改变函数本身或传递给它的结构。

您可能会问为什么所有的核心结构都有 sTypepNext,即使您将它们传递给带有类型指针而不是空指针的函数。原因是一致性,因为您永远不知道什么时候可能需要现有结构作为链的一部分以进行某些新扩展。

If we dont have any options anyway, why is this parameter not just set implicitly upon creation of the type?

因为 C 不是 C++。没有办法在 C 中声明一个结构并说该结构的这一部分将始终具有该值。在 C++ 中,您可以通过将某些内容声明为 const 并提供初始默认值。事实上,我喜欢 Vulkan C++ 绑定的一个原因是你基本上可以永远忘记 sType。如果您使用的是扩展程序,您仍然需要根据需要填充 pNext