POD-struct或标准布局类型的成员是否保证按照它们的对齐要求进行对齐?

14

假设在C++03中给定一个POD-struct,或者在C++11中给定一个标准布局类型,并且所有成员都具有基本对齐要求,那么每个成员是否保证根据其对齐要求对齐?

换句话说,对于标准布局类型的所有成员…

  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结构体中成员的对齐是不确定的。C++03标准对此不做规定,但应该按照对象类型的对齐方式进行内存分配。结构体成员间可能存在填充,但这取决于实现的对齐要求。在POD结构体中,第一个成员将按照结构体的对齐方式进行对齐。
还需要引用标准的以下部分:
1.8 The C++ object model [intro.object] 1.8/1 The constructs in a C++ program create, destroy, refer to, access, and manipulate objects. An object is a region of storage.
3.9 Types [basic.types] 3.9/5 Object types have alignment requirements (3.9.1, 3.9.2). The alignment of a complete object type is an implementation-defined integer value representing a number of bytes; an object is allocated at an address that meets the alignment requirements of its object type.
3.9.1 Fundamental types [basic.fundamental] 3.9.1/3 For each of the signed integer types, there exists a corresponding (but different) unsigned integer type: "unsigned char", "unsigned short int", "unsigned int", and "unsigned long int," each of which occupies the same amount of storage and has the same alignment requirements (3.9) as the corresponding signed integer type;...
9.2 Class members [class.mem] 9.2/12 Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).
9.2/17 A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment.]

1
在涉及对齐要求的“对象”一词中,“对象”指的是“对象”,而不仅仅是“最复合对象”。 (即关于复合类型的定义,其中指出“包含各种类型的对象序列的类”。) - rici
@rici:谢谢。我已经从规范中添加了对象的定义:“一段存储区域”。 - Ross Bencina
1
罗斯: 正确。这是一个存储区域,而不是独立的存储区域。复合对象中的对象仍然是对象,因此仍然受到对齐要求的影响。9.2/17 中的条件语句(“可能”)只是承认对齐要求可能需要填充或不需要填充的标准;它并不允许避开对齐要求。 - rici
2个回答

11

POD结构体的每个元素本身都是一个对象,而对象只能按照这些对象的对齐要求来分配。然而,对齐要求可能会因为某些事情是另一个对象的子对象而改变([basic.align]/1,2)。

1 对象类型具有对齐要求(见3.9.1、3.9.2),这些要求限制了可以分配该类型对象的地址。对齐是一个实现定义的整数值,表示分配给给定对象的连续地址之间的字节数。对象类型对该类型的每个对象都施加对齐要求;可以使用对齐说明符(7.6.2)请求更严格的对齐。

2 基本对齐由小于或等于在所有上下文中实现支持的最大对齐方式所代表,它等于alignof(std::max_align_t) (18.2)。当作为完整对象的类型和作为子对象的类型时,需要的对齐方式可能不同。[示例:

struct B { long double d; };
struct D : virtual B { char c; }

当完整对象的类型是D时,它将具有类型为B的子对象,因此必须适当地对齐以用于long double。如果D出现在另一个也具有B作为虚基类的对象的子对象中,则B子对象可能是不同子对象的一部分,从而降低了D子对象的对齐要求。

[示例结束]

alignof运算符的结果反映了完整对象情况下类型的对齐要求。

[强调添加]

虽然示例通过继承引用子对象,但规范措辞仅涉及子对象,因此我认为相同的规则适用,因此一方面您可以假定每个子对象都对齐以便访问。另一方面,不能保证这将是alignof给出的相同对齐方式。

[参考来源为N4296,但我认为所有最近版本都适用。当然,C++98/03根本没有alignof,但我认为相同的基本原理适用--成员将被对齐以便使用,但该对齐要求并不一定与它们作为独立对象使用时相同。]


1
@rici 不,它不必至少是那样的。子对象对齐要求的重点在于它们可以更弱。 - Columbo
@Columbo:子对象对齐方式不能小于基本类型的基本对齐方式。但我同意我的断言需要限定。 - rici
关于:“当一个类型被用作完整对象的类型和子对象的类型时,所需的对齐方式可能不同。” > 如果该类型保证是基本类型,那会改变什么吗? - Ross Bencina
@Columbo,我确实感谢您提供的额外澄清细节,说明了问题可能出错的地方,但请注意,问题特别涉及具有“基本对齐要求”的成员子对象(请参见问题的第一段)。 - Ross Bencina
1
@RossBenica 那有什么区别呢?如果 int 的通常对齐方式是 4,为什么我不能在结构体中每 1 个字节对齐一个 int 呢? - Columbo
显示剩余11条评论

6

每种类型有两个不同的对齐要求。一个对应于完整对象,另一个对应于子对象。[basic.align]/2:

The alignment required for a type might be different when it is used as the type of a complete object and when it is used as the type of a subobject. [ Example:

struct B { long double d; };
struct D : virtual B { char c; };

When D is the type of a complete object, it will have a subobject of type B, so it must be aligned appropriately for a long double. If D appears as a subobject of another object that also has B as a virtual base class, the B subobject might be part of a different subobject, reducing the alignment requirements on the D subobject. —end example ] The result of the alignof operator reflects the alignment requirement of the type in the complete-object case.

我无法为成员子对象想出任何具体的例子 - 肯定没有!- 但上面的段落承认了这样一种可能性,即成员子对象的对齐方式比 alignof 所产生的要弱,这将不符合您的条件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接