ngo*_*eff 8 c++ memory gcc struct visual-c++
C++结构的布局是由标准设置的,还是至少在编译器之间是通用的?
我有一个结构,其中一个成员需要在16字节边界上对齐,如果我能保证字段的顺序,这将更容易.
另外,对于非虚拟类,第一个元素的地址是否也可能是结构的地址?
我对GCC和MSVS最感兴趣.
Jer*_*fin 13
C和C++都保证字段将按照您定义的顺序在内存中布局.对于C++,只保证POD类型1(任何合法的C结构[编辑:C89/90 - 不是,例如,C99 VLA]也有资格作为POD).
编译器可以在成员之间和/或结构的末尾自由插入填充.大多数编译器为您提供了一些控制它的方法(例如#pragma pack(N)
),但它在编译器之间有所不同.
1好吧,有一个他们没有想到的角落案例,它不能保证POD类型 - 访问说明符打破了订购保证:
struct x {
int x;
int y;
public:
int z;
};
Run Code Online (Sandbox Code Playgroud)
这是一种POD类型,但public:
介于两者之间y
,z
意味着它们理论上可以重新排序.我很确定这纯粹是理论上的 - 我不知道在这种情况下是否会对成员进行重新排序的任何编译器(除非内存使我失败甚至比平时更糟,这在C++ 0x中得到修复).
编辑:标准的相关部分(至少大部分)是§9/ 4:
POD结构是一个聚合类,它没有指向成员,非POD结构,非POD联合(或此类类型的数组)或引用的类型指针的非易失性数据成员,并且没有用户定义的副本赋值运算符,没有用户定义的析构函数.
和§8.5.1/ 1:
聚合是一个数组或类(第9节),没有用户声明的构造函数(12.1),没有私有或受保护的非静态数据成员(第11节),没有基类(第10节),没有虚函数(10.3) .
和§9.2/ 12:
...未指定由访问说明符分隔的非静态数据成员的分配顺序(11.1).
虽然这受到§9.2/ 17的限制:
指向POD-struct对象的指针,使用reinterpret_cast进行适当转换,指向其初始成员...
因此,(即使前面带有a public:
,您定义的第一个成员必须首先在内存中.public:
理论上可以重新排列由说明符分隔的其他成员.
我还应该指出,对此有一些争论的余地.特别是,§9.2/ 14中也有一条规则:
如果两个POD-struct(第9节)类型具有相同数量的非静态数据成员,则它们是布局兼容的,并且相应的非静态数据成员(按顺序)具有布局兼容类型(3.9).
因此,如果你有类似的东西:
struct A {
int x;
public:
int y;
public:
int z;
};
Run Code Online (Sandbox Code Playgroud)
它需要与以下版面兼容:
struct B {
int x;
int y;
int z;
};
Run Code Online (Sandbox Code Playgroud)
我很确定这是/ 意图是两个结构的成员必须在内存中以相同的方式布局.由于第二个显然不能重新安排其成员,所以第一个也不应该重新排列.不幸的是,标准从未真正定义"布局兼容"的含义,使得论证充其量只是微弱.
C++继承了c在许多平台上有效工作的需要/愿望,因此将某些事情留给了编译器.除了要求元素以指定顺序出现之外,这也是其中之一.
但是许多编译器支持#pragma
s和选项,让你建立控制包装.请参阅编译器的文档.