Has*_*iri 5 c++ struct structlayout vulkan
我刚从VC++ 14.0(2015)编译器中的Bug中学到了什么?那个人不应该假设结构的布局最终会在内存中出现.但是,我不明白我见过很多代码中的常见做法.例如,Vulkan图形API执行以下操作:
定义结构
struct {
glm::mat4 projection;
glm::mat4 model;
glm::vec4 lightPos;
} uboVS;
Run Code Online (Sandbox Code Playgroud)
然后填补其领域:
uboVS.model = ...
uboVS....
Run Code Online (Sandbox Code Playgroud)
然后通过memcpy将结构(在主机内存中)复制到设备内存:
uint8_t *pData;
vkMapMemory(device, memory, 0, sizeof(uboVS), 0, (void **)&pData);
memcpy(pData, &uboVS, sizeof(uboVS));
vkUnmapMemory(device, memory);
Run Code Online (Sandbox Code Playgroud)
然后到GPU,它定义了一个UBO来匹配该结构:
layout (binding = 0) uniform UBO
{
mat4 projection;
mat4 model;
vec4 lightPos;
} ubo;
Run Code Online (Sandbox Code Playgroud)
然后,在GPU方面,ubo将始终匹配uboVS.
这是不一样的未定义行为?那些代码是否依赖于uboVS结构完全按照定义布局,或者双方(编译的C++代码和编译的SPIR-V着色器)基本上生成相同的不同结构布局?(类似于https://www.securecoding.cert.org/confluence/display/c/EXP11-C.+Do+not+make+assumptions+regarding+the+layout+of+structures+with+中的第一个示例位域)
这个问题并不是特定于Vulkan或图形API,我很好奇人们可以假设什么,以及什么时候只使用结构作为一块内存.我理解结构打包和对齐,但还有更多吗?
谢谢
重要的是要认识到你在引用的问题中做了什么和你在这里做了什么之间的区别.
你在所展示的问题中做了什么违反了C++的规则.它调用未定义的行为.您试图假装包含16个浮点数的对象与16个浮点数组相同.C++不允许这是明确定义的行为,并且允许编译器假设您不会尝试它.
相比之下,将结构转换为字节数组并将该数组复制到其他地方实际上并不会破坏C++对象模型的规则.它有一个非常具体的条款允许适当类型的事情.
不同之处在于,关注对象布局的不是C++编译器 ; 这是GPU.只要您提供的数据布局与着色器所说的相匹配,您就可以了.您没有将浮动数据转换为数组或尝试通过指向另一个对象或某些对象来访问一个对象.你只是复制字节.
此时,唯一的问题是该结构的字节表示是否与预期的SPIR-V数据结构定义的字节表示相匹配.是的,这是Vulkan可以运行的大多数系统可以依赖的东西.
确实,粗略地说,C++标准并没有要求任何特定的类成员内部布局.
但是,专用库(如特定操作系统的图形库)将针对操作系统的特定编译器.他们知道这个特定的编译器如何安排C/C++类和结构成员的布局,并且库将提供与所讨论的实际硬件相匹配的合适定义.
具有多个编译器的操作系统通常具有该操作系统的二进制ABI的正式规范,并且编译器将遵循该ABI,并且专业库将提供与其同步的类和结构定义.
因此,在您的具体情况下,在查阅编译器的文档后,您可以"假设并且何时可以使用结构作为一块内存",确定编译器如何布局结构或类的成员,然后来相应地结构布局.