Vulkan-hpp 是 reinterpret_casting 非标准布局 class 到另一个 class。这是合法的吗?
Vulkan-hpp is reinterpret_casting non-standard-layout class to another class. Is this legal?
所以最近我一直在使用 Vulkan-Hpp
(Vulkan Api、Github Link 的官方 c++ 绑定)。
查看源代码,我发现他们围绕原生 Vulkan 结构创建包装器 类(例如 vk::InstanceCreateInfo
围绕 VkInstanceCreateInfo
)。 (注意:环绕,而不是从派生)
调用本机 Vulkan API 时,指向包装器 类 的指针被 reinterpret_cast
编辑到本机 Vulkan 结构中。使用 vk::InstanceCreateInfo
:
的示例
//definition of vk::InstanceCreateInfo
struct InstanceCreateInfo
{
/* member function omitted */
private:
StructureType sType = StructureType::eInstanceCreateInfo;
public:
const void* pNext = nullptr;
InstanceCreateFlags flags;
const ApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
};
//definition of 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;
} VkInstanceCreateInfo;
//And the usage where reinterpret_cast takes place
template<typename Dispatch>
VULKAN_HPP_INLINE ResultValueType<Instance>::type createInstance( const InstanceCreateInfo &createInfo, Optional<const AllocationCallbacks> allocator, Dispatch const &d )
{
Instance instance;
Result result = static_cast<Result>( d.vkCreateInstance( reinterpret_cast<const VkInstanceCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkInstance*>( &instance ) ) );
return createResultValue( result, instance, VULKAN_HPP_NAMESPACE_STRING"::createInstance" );
}
所以我的问题是:vk::InstanceCreateInfo
和VkInstanceCreateInfo
是两种不同的类型。此外,VkInstanceCreateInfo
是标准布局,但 vk::InstanceCreateInfo
不是(因为它具有混合访问说明符)。在这两种类型的指针之间 reinterpret_cast
ing 是否合法(由 Vulkan-Hpp
完成)?这是否违反了严格的别名规则?
注意:您可以假设 VkInstanceCreateFlags
和 vk::InstanceCreateFlags
在这种情况下可以互换(否则会使我的问题递归)
就标准而言,是的,通过指向 VkInstanceCreateInfo
对象的指针访问 vk::InstanceCreateInfo
对象违反了严格的别名。即使两种类型都是具有等效布局的标准布局,它仍然会违反严格的别名。该标准不允许您假装一种 class 类型是另一种类型,即使它们具有相同的布局。
所以这段代码依赖于某些 implementation-specific 行为。
错了吗?为每个 Vulkan 接口函数调用做一个额外的副本会让你感觉更好吗,即使没有它也能工作?最终取决于您愿意容忍多少 UB。
所以最近我一直在使用 Vulkan-Hpp
(Vulkan Api、Github Link 的官方 c++ 绑定)。
查看源代码,我发现他们围绕原生 Vulkan 结构创建包装器 类(例如 vk::InstanceCreateInfo
围绕 VkInstanceCreateInfo
)。 (注意:环绕,而不是从派生)
调用本机 Vulkan API 时,指向包装器 类 的指针被 reinterpret_cast
编辑到本机 Vulkan 结构中。使用 vk::InstanceCreateInfo
:
//definition of vk::InstanceCreateInfo
struct InstanceCreateInfo
{
/* member function omitted */
private:
StructureType sType = StructureType::eInstanceCreateInfo;
public:
const void* pNext = nullptr;
InstanceCreateFlags flags;
const ApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
};
//definition of 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;
} VkInstanceCreateInfo;
//And the usage where reinterpret_cast takes place
template<typename Dispatch>
VULKAN_HPP_INLINE ResultValueType<Instance>::type createInstance( const InstanceCreateInfo &createInfo, Optional<const AllocationCallbacks> allocator, Dispatch const &d )
{
Instance instance;
Result result = static_cast<Result>( d.vkCreateInstance( reinterpret_cast<const VkInstanceCreateInfo*>( &createInfo ), reinterpret_cast<const VkAllocationCallbacks*>( static_cast<const AllocationCallbacks*>( allocator ) ), reinterpret_cast<VkInstance*>( &instance ) ) );
return createResultValue( result, instance, VULKAN_HPP_NAMESPACE_STRING"::createInstance" );
}
所以我的问题是:vk::InstanceCreateInfo
和VkInstanceCreateInfo
是两种不同的类型。此外,VkInstanceCreateInfo
是标准布局,但 vk::InstanceCreateInfo
不是(因为它具有混合访问说明符)。在这两种类型的指针之间 reinterpret_cast
ing 是否合法(由 Vulkan-Hpp
完成)?这是否违反了严格的别名规则?
注意:您可以假设 VkInstanceCreateFlags
和 vk::InstanceCreateFlags
在这种情况下可以互换(否则会使我的问题递归)
就标准而言,是的,通过指向 VkInstanceCreateInfo
对象的指针访问 vk::InstanceCreateInfo
对象违反了严格的别名。即使两种类型都是具有等效布局的标准布局,它仍然会违反严格的别名。该标准不允许您假装一种 class 类型是另一种类型,即使它们具有相同的布局。
所以这段代码依赖于某些 implementation-specific 行为。
错了吗?为每个 Vulkan 接口函数调用做一个额外的副本会让你感觉更好吗,即使没有它也能工作?最终取决于您愿意容忍多少 UB。