C++ C/C+中的内存对齐+;

C++ C/C+中的内存对齐+;,c++,c,memory,memory-management,C++,C,Memory,Memory Management,我正在读游戏编码第四版。有一个关于记忆对齐的话题。在下面的代码中,作者说第一个结构非常慢,因为它既不是位对齐的,也不是字节对齐的。第二个不是位对齐的,而是字节对齐的。最后一个很快,因为两者都有。他说,如果没有pragma,编译器将对齐内存本身,从而造成内存浪费。我真的无法计算 这是正文的一部分:- 如果让编译器通过添加未使用的代码来优化SlowStruct 字节,每个结构将是24字节,而不是14字节。七 在第一个char变量之后填充额外的字节,并且 剩余字节添加到末尾。这确保了整个 结构总是从8

我正在读游戏编码第四版。有一个关于记忆对齐的话题。在下面的代码中,作者说第一个结构非常慢,因为它既不是位对齐的,也不是字节对齐的。第二个不是位对齐的,而是字节对齐的。最后一个很快,因为两者都有。他说,如果没有pragma,编译器将对齐内存本身,从而造成内存浪费。我真的无法计算

这是正文的一部分:-

如果让编译器通过添加未使用的代码来优化SlowStruct 字节,每个结构将是24字节,而不是14字节。七 在第一个char变量之后填充额外的字节,并且 剩余字节添加到末尾。这确保了整个 结构总是从8字节边界开始。大约40% 所有这些都是由于对成员变量的不小心排序造成的

以下是粗体结尾行:-

不要让编译器浪费宝贵的内存空间。放一些你的 脑细胞工作并调整自己的成员变量。

请给我看一下计算结果,并更清楚地解释填充概念

代码:-

#pragma pack(push, 1)
struct ReallySlowStruct
{
    char c : 6;
    __int64 d : 64;
    int b : 32;
    char a : 8;
};

struct SlowStruct
{
    char c;
    __int64 d;
    int b;
    char a;
};

struct FastStruct
{
   __int64 d;
   __int b;
   char a;
   char c;
   char unused[2];
};
#pragma pack(pop)

书中给出的示例高度依赖于所使用的编译器和计算机体系结构。如果你在自己的程序中测试它们,你可能会得到与作者完全不同的结果。我将假设一个64位的体系结构,因为根据我在描述中读到的内容,作者也会这样做。 让我们逐一看一下示例:

ReallySlowStruct 如果使用的编译器支持非字节对齐的结构成员,“d”的开头将位于结构第一个字节的第七位。听起来很有利于节省内存。问题是,C不允许位寻址。因此,为了将newValue保存到“d”成员,编译器必须执行大量的位移位操作:将“newValue”的前两位保存为字节0,向右移位6位。然后将“newValue”两位向左移位,并从字节1开始保存。字节1是一个未对齐的内存位置,这意味着大容量内存传输指令无法工作,编译器必须一次保存每个字节

SlowStruct 情况好转了。编译器可以消除所有的位篡改。但是写入“d”仍然需要一次写入每个字节,因为它没有与本机的“int”大小对齐。64位系统上的本机大小为8。因此,每个不能被8整除的内存地址一次只能访问一个字节。更糟糕的是,如果我关闭打包,我将浪费大量的内存空间:每个后跟int的成员都将填充足够的字节,以使整数从一个可被8整除的内存位置开始。在这种情况下:字符a和c都将占用8个字节

FastStruct 这与目标计算机上int的大小一致。“d”应该占用8个字节。因为字符都捆绑在一个地方,所以编译器不会填充它们,也不会浪费空间。每个字符只有1个字节,所以我们不需要填充它们。整个结构的总大小为16字节。可除以8,因此无需填充


在大多数情况下,您不必担心对齐,因为默认对齐已经是最佳的。但是,在某些情况下,通过为数据结构指定自定义对齐方式,可以显著提高性能或节省内存

在内存空间方面,编译器以一种自然对齐结构中每个元素的方式填充结构

struct x_
{
   char a;     // 1 byte
   int b;      // 4 bytes
   short c;    // 2 bytes
   char d;     // 1 byte
} bar[3];
struct x
由编译器填充,因此成为:

// Shows the actual memory layout
struct x_
{
   char a;           // 1 byte
   char _pad0[3];    // padding to put 'b' on 4-byte boundary
   int b;            // 4 bytes
   short c;          // 2 bytes
   char d;           // 1 byte
   char _pad1[1];    // padding to make sizeof(x_) multiple of 4
} bar[3];

来源:

它既不是位对齐的,也不是字节对齐的。位对齐?我不明白,C中的最小可寻址地址是一个字节,不是吗?.related/dupe:还有这个wiki:@KeineLust我说错了。它未在位边界对齐。@NathanOliver我正在检查您提供的链接,我将查看是否还有任何疑问。谢谢大家,谢谢你们回答我的问题。刚才我从不同的链接运行了一些代码,在书中给出了这些代码,并运行了一些实验。我清楚地知道,填充并没有特定的标准。但作者暗示,为了提高性能,应该以适当的方式了解编译器填充规则和顺序声明。你的回答也非常有用。谢谢。我犯了FastStruct代码中的错误。我忘了添加64 int var。对不起。请相应地更新答案。感谢您更正答案。我感谢你的帮助,现在我相信我已经理解了这个话题。再次感谢。在您对FastStruct的解释中,您提到“b”占用8个字节。那不应该是“d”吗?