该标准相当具体,即使是 POD 结构(我认为这是最严格的结构类)也可以在成员之间进行填充。 (“因此,POD 结构对象内可能有未命名的填充,但不是在其开头,这是实现适当对齐所必需的。”——非规范注释,但仍然使意图非常明确)。
例如,对比标准布局结构的要求(C++11,§1.8/4):
普通可复制或标准布局类型(3.9)的对象应占用连续的存储字节。”
...对于数组(§8.3.4/1):
数组类型的对象包含连续分配的 N 个类型为 T 的子对象的非空集合。
在数组中,elements它们本身需要连续分配,而在结构体中,只有storage要求是连续的。
可能使“连续存储”要求更有意义的第三种可能性是考虑不可简单复制或标准布局的结构/类。在这种情况下,存储可能根本不连续。例如,一种实现可能会留出一个内存区域来保存所有私有变量,并留出一个完全独立的内存区域来保存所有公共变量。为了使这一点更加具体,请考虑两个定义,例如:
class A {
int a;
public:
int b;
} a;
class B {
int x;
public:
int y;
} b;
通过这些定义,内存的布局可能类似于:
a.a;
b.x;
// ... somewhere else in memory entirely:
a.b;
b.y;
在这种情况下,两个元素都没有nor存储需要是连续的,因此完全独立的结构/类的交错部分是允许的。
也就是说,第一个元素必须与整个结构位于同一地址 (9.2/17):“指向 POD 结构对象的指针,使用 reinterpret_cast 进行适当转换,指向其初始成员(或者如果该成员是一个位字段,然后是它所在的单元),反之亦然。”
在您的情况下,您有一个 POD 结构,因此(§9.2/17):“指向 POD 结构对象的指针,使用 reinterpret_cast 进行适当转换,指向其初始成员(或者如果该成员是位字段) ,然后到其所在的单位),反之亦然。”从第一个成员开始must对齐,并且其余成员都是相同类型,因此其他成员之间不可能真正需要任何填充(即,除了位字段之外,您可以放入结构中的任何类型也可以放入数组,其中需要连续分配元素)。如果您的元素小于单词,那么在面向单词的机器(例如早期的 DEC Alphas)上,填充可能会使访问变得更简单。例如,早期的 DEC Alpha(在硬件级别)一次只能读/写一个完整的(64 位)字。因此,让我们考虑一个由四个组成的结构char
要素:
struct foo {
char a, b, c, d;
};
如果需要将它们放在内存中以便它们是连续的,则访问foo::b
(例如)需要 CPU 加载该字,然后将其右移 8 位,然后掩码对该字节进行零扩展以填充整个寄存器。
存储会更糟 - CPU 必须加载整个字的当前值,屏蔽掉相应字符大小部分的当前内容,将新值移动到正确的位置,或者将其放入字中,最后存储结果。
相比之下,通过元素之间的填充,每个元素都变成简单的加载/存储,没有移位、屏蔽等。
至少如果没记错的话,使用 DEC 的 Alpha 正常编译器,int
是 32 位,并且long
是 64 位(早于long long
)。因此,用你的四个结构int
s,您可能会期望在元素之间看到另外 32 位的填充(以及最后一个元素之后的另外 32 位)。
鉴于您确实有 POD 结构,但您仍然有一些可能性。我可能更喜欢使用offsetof
要获取结构体成员的偏移量,请创建它们的数组,并通过这些偏移量访问成员。我展示了如何在couple https://stackoverflow.com/a/5088496/179910 of 以前的答案 https://stackoverflow.com/a/2043949/179910.