C++ 结构可以在不同的编译时间有不同的对齐方式吗?

Posted

技术标签:

【中文标题】C++ 结构可以在不同的编译时间有不同的对齐方式吗?【英文标题】:Can C++ structs have different alignments at different compilation times? 【发布时间】:2020-11-23 02:46:01 【问题描述】:

我有一些代码在过去与glm 一起工作的低级别上工作。我将 glm 的所有用法切换为 Eigen 现在我观察到一个奇怪的行为,即同一个结构似乎在代码的不同点具有不同的对齐方式。

这是 gdb 在初始化后给我的:

(gdb) p sizeof(CellShadingInfo)
$1 = 240
(gdb) 

现在让我们看看具体全局结构的构造:

const std::unordered_map<std::string, size_t> uniform_size_map = 
    "GuiTransform", sizeof(GuiTransform),
    "UniformBufferObject", sizeof(UniformBufferObject),
    "GuiVisualProperties", sizeof(GuiVisualProperties),
    "PostProcessingEffects", sizeof(PostProcessingEffects),
    "LineProperties", sizeof(LineProperties),
    "PointInfo", sizeof(PointInfo),
    "GaussianVisualization", sizeof(GaussianVisualization),
    "ParticleUBO", sizeof(ParticleUBO),
    "CameraInfo", sizeof(CameraInfo),
    "MVPOnlyUbo", sizeof(MVPOnlyUbo),
    "WireframeDebugInfo", sizeof(WireframeDebugInfo),
    "CellShadingInfo", sizeof(CellShadingInfo),
    "GaussianProperties", sizeof(GaussianProperties)
;

这是全局的,所以它的初始化代码会在 main 之前运行。但由于 LUP 已被定义为常量,因此其中的所有值都应该是最终值,从而防止意外覆盖。

但是根据gdb:

(gdb) p uniform_size_map 
$2 = std::unordered_map with 13 elements = ["CellShadingInfo"] = 228, ["MVPOnlyUbo"] = 192, ["ParticleUBO"] = 16, 
  ["GaussianVisualization"] = 48, ["PointInfo"] = 36, ["PostProcessingEffects"] = 8, ["GuiVisualProperties"] = 20, 
  ["GaussianProperties"] = 8, ["CameraInfo"] = 12, ["UniformBufferObject"] = 192, ["WireframeDebugInfo"] = 16, 
  ["LineProperties"] = 40, ["GuiTransform"] = 16

所以我唯一的解释是编译器在 preinit 方法与常规运行时的编译过程中使用了不同的对齐方式。然而,这听起来很荒谬。

【问题讨论】:

我的猜测是,CellShadingInfo 有几个不同的定义,或者在不同的命名空间中(没关系),或者在相同的命名空间中但在不同的翻译单元中(这违反了 ODR)。也许有一些成员被包含或排除,或者基于宏改变类型;并且不同的翻译单元使用定义的不同宏进行编译。 整个程序中只有一个 CellShadingInfo 声明(刚刚用 grep 检查),我正在使用的宏处理器的唯一用途是通过包含。这会导致问题吗? 嗯,它可能类似于struct CellShadingInfo SomeType x;,其中SomeType 的定义因翻译单元而异。或者可能有一个数组,其边界由一个变化的常数定义。违反 ODR 的方式有很多种。 "SomeType 的定义因翻译单元而异" 我 100% 确定这发生在 Eigen 向量中。该结构有很多,但其他一切都只是普通的整数和浮点数,所以这就是问题所在。我该如何解决? 找出它们最终不同的原因,确保所有翻译单元的构建配置一致。 【参考方案1】:

问题是编译问题。由于未知原因,目标文件无法编译,因此链接器正在查找旧目标文件并针对该文件进行链接。由于该目标文件是由旧的源代码制成的,因此该结构在代码的不同部分不再具有相同的对齐方式。

【讨论】:

以上是关于C++ 结构可以在不同的编译时间有不同的对齐方式吗?的主要内容,如果未能解决你的问题,请参考以下文章

C++基本知识点总结(网摘)

转载c++面试题

GCC和G ++结构包装的区别?

C++ 类和对象上

可以通过以下方式将结构转换为不同的大小吗?

关于结构体内存对齐方式的总结(#pragma pack()和alignas())