【发布时间】:2015-09-21 16:20:19
【问题描述】:
给定一个 POD 结构(在 C++03 中)或标准布局类型(在 C++11 中),所有成员都有基本对齐要求,是否保证每个成员都按照它的对齐要求?
换句话说,对于标准布局类型 S 的 { m0 ... mn } 中的所有成员 m_k,
struct S {
T0 m0;
T1 m1;
...
TN mn;
};
以下表达式的计算结果是否保证为true?
(offsetof(S,m_k) % alignof(decltype(S::m_k))) == 0
请给出 C++03 和 C++11 的答案并引用标准的相关部分。来自 C 标准的支持证据也会有所帮助。
我对 C++03 标准 (ISO/IEC 14882:2003(E)) 的解读是,除了第一个成员外,它对 POD 结构中成员的对齐保持沉默。相关段落是:
在规范的语言中,对象是一个“存储区域”:
1.8 C++ 对象模型 [intro.object]
1.8/1 C++ 程序中的构造创建、销毁、引用、访问和操作对象。对象是一个存储区域。 ...
对象根据对齐要求进行分配:
3.9 类型 [basic.types]
3.9/5 对象类型有对齐要求(3.9.1、3.9.2)。一个完整对象类型的对齐是一个实现定义的整数值,表示字节数; 对象分配在满足其对象类型对齐要求的地址。
基本类型有对齐要求:
3.9.1 基本类型 [basic.fundamental]
3.9.1/3 对于每一种有符号整数类型,都存在对应的(但不同的)无符号整数类型:“unsigned char”、“unsigned short int”、“unsigned int”和“unsigned long int”, " 每个都占用相同的存储量和对应的有符号整数类型具有相同的对齐要求(3.9);...
填充可能由于“实现对齐要求”而发生:
9.2 类成员 [class.mem]
9.2/12 在没有中间访问说明符的情况下声明的(非联合)类的非静态数据成员被分配,以便后面的成员在类对象中具有更高的地址。非静态的分配顺序 由访问说明符分隔的数据成员未指定 (11.1)。 实施对齐要求可能会导致两个相邻的成员不能紧挨着分配;管理虚拟功能 (10.3) 和虚拟基类 (10.1) 的空间要求也是如此。
9.2/12 中的“已分配”一词是否与 3.9/5 中的“已分配”具有相同的含义?规范中“已分配”的大多数用法是指动态存储分配,而不是结构内部布局。在 9.2/12 中使用 may 似乎暗示 3.9/5 和 3.9.1/3 的对齐要求可能对结构成员没有严格要求。
POD-struct 的第一个成员将根据结构的对齐要求进行对齐:
9.2/17 指向 POD 结构对象的指针,使用 reinterpret_cast 适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。 [注意:因此,在 POD 结构对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的。 ]
[在上述所有引号中都添加了重点。]
【问题讨论】:
-
对齐要求中的“对象”一词的意思是“对象”,而不仅仅是“最复合的对象”。 (即复合类型的定义,其中它说“包含各种类型的一系列对象的类”。)
-
@rici:谢谢。我从规范中添加了对象的定义:“存储区域”。
-
罗斯:正确。一个存储区域。不是一个独立的存储区域。复合对象中的对象仍然是对象,因此仍受对齐要求的约束。 9.2/17 中的条件(“可能”)只是承认对齐要求可能需要或可能不需要填充;不允许避免对齐要求。
标签: c++ c++11 language-lawyer memory-alignment c++03