【发布时间】:2010-09-26 17:47:51
【问题描述】:
如果结构成员的对齐方式已知,是否可以找到结构类型的对齐方式?
例如。为:
struct S
{
a_t a;
b_t b;
c_t c[];
};
是S = max(alignment_of(a),alignment_of(b),alignment_of(c))的对齐方式吗?
在互联网上搜索我发现“对于结构化类型,其任何元素的最大对齐要求决定了结构的对齐方式”(What Every Programmer Should Know About Memory)但我在标准中找不到任何类似的东西(最新草案更准确地说)。
已编辑: 非常感谢您提供的所有答案,尤其是 Robert Gamble,他为原始问题提供了非常好的答案以及其他做出贡献的人。
简而言之:
为确保结构成员的对齐要求,结构的对齐必须至少与其最严格的成员的对齐一样严格。
至于确定结构的对齐方式,提出了几个选项,经过一些研究,我发现:
- c++ std::tr1::alignment_of
- 尚不标准,但接近(技术报告1),应该在C++0x中
- 最新草案中存在以下限制: 前提条件:T 应为完整类型、引用类型或
未知界限,但不应是函数类型或(可能
cv 合格)无效。
- 这意味着我提出的使用 C99 灵活数组的用例将不起作用(这并不奇怪,因为灵活数组不是标准 c++)
- 在最新的 c++ 草案中,它是用一个新关键字 - alignas 定义的(这具有相同的完整类型要求)
- 在我看来,如果 c++ 标准支持 C99 灵活数组,则可以放宽要求(结构与灵活数组的对齐方式不应根据数组元素的数量而改变)
- c++ boost::alignment_of
- 主要是 tr1 替换
- 似乎专门针对 void 并在这种情况下返回 0(这在 c++ 草案中是被禁止的)
- 来自开发人员的注意事项:严格来说,您应该只依赖 ALIGNOF(T) 的值是 T 的真实对齐方式的倍数,尽管在实践中它确实在我们所知道的所有情况下计算正确的值。李>
- 我不知道这是否适用于灵活数组,它应该(通常可能无法正常工作,这会解析为我平台上的编译器内在,所以我不知道它在一般情况下会如何表现)
- Andrew Top 提出了一个简单的模板解决方案,用于计算答案中的对齐方式
- 这似乎与 boost 所做的非常接近(据我所知,如果它小于计算出的对齐,boost 将另外返回对象大小作为对齐)所以可能同样的通知适用
- 这适用于灵活的数组
- 使用 Windbg.exe 找出符号的对齐方式
- 不是编译时间,特定于编译器,没有测试过
- 在包含该类型的匿名结构上使用 offsetof
- 查看答案,不可靠,不能用 c++ non-POD 移植
- 编译器内在函数,例如。 MSVC __alignof
- 适用于灵活的数组
- alignof 关键字在最新的 c++ 草案中
如果我们想使用“标准”解决方案,我们仅限于使用 std::tr1::alignment_of,但是如果您将 c++ 代码与 c99 的灵活数组混合使用,那将无法正常工作。
正如我所见,只有 1 个解决方案 - 使用旧的 struct hack:
struct S
{
a_t a;
b_t b;
c_t c[1]; // "has" more than 1 member, strictly speaking this is undefined behavior in both c and c++ when used this way
};
在这种情况下(以及所有其他情况),令人遗憾的是,c 和 c++ 标准的分歧及其日益扩大的差异。
另一个有趣的问题是(如果我们无法以可移植的方式找出结构的对齐方式)可能最严格的对齐要求是什么。我可以找到几个解决方案:
- boost(内部)使用多种类型的并集,并在其上使用 boost::alignment_of
- 最新的 c++ 草案包含 std::aligned_storage
- 对于大小不大于 Len 的任何 C++ 对象类型,default-alignment 的值应是最严格的对齐要求
- 所以
std::alignment_of< std::aligned_storage<BigEnoughNumber>>::value应该给我们最大的对齐方式 - 仅草稿,还不是标准(如果有的话),
tr1::aligned_storage没有此属性
- 所以
- 对于大小不大于 Len 的任何 C++ 对象类型,default-alignment 的值应是最严格的对齐要求
对此的任何想法也将不胜感激。
我已暂时取消选中已接受的答案,以便在新的子问题上获得更多可见性和输入
【问题讨论】:
-
底线是只有编译器知道它在编译时将如何对齐对象,因此获取此信息的唯一方法是从编译器。在标准化之前,您将需要使用编译器扩展。你在做什么需要这些信息?
-
虚拟机(对象、数组、垃圾收集器和许多其他杂项所需的低级构造)。这是一个学生项目,应该尽可能“便携”和“符合标准”。
-
让它工作不是问题(而且大部分已经完成),但我没有时间在多个平台和编译器上测试项目,所以我正在寻找一些符合标准的解决方案我面临的问题。
-
我确实意识到这在标准方面很难做到。我已经总结了这些信息,希望它对寻找相同事物的其他人有所帮助。 (cmets 300 个字符的限制是荒谬的)
-
至于标准,我也很失望,因为在最新的 C 草案中几乎没有提到对齐 - 几年后,c++ 可能会变得比 C 更“低级”,因为它的alignof 和对齐关键字 :)