【问题标题】:How does compiler allocates memory to this struct? [duplicate]编译器如何为这个结构分配内存? [复制]
【发布时间】:2013-07-20 09:40:15
【问题描述】:

我在尝试使用命名空间和结构时遇到了问题。

C++

#include<iostream>
using namespace std;

namespace One
{
    struct Data
    {
        int val;
        char character;
    };
}

namespace Two
{
    struct Data
    {
        int val;
        bool boolean;
    };
}

void functionOne(void)
{
    using namespace One;
    cout << "functionOne()" << endl;
    cout << "The size of struct Data : ";
    cout << sizeof(Data) << endl;
}

void functionTwo(void)
{
    using namespace Two;
    cout << "functionTwo()" << endl;
    cout << "The size of struct Data : ";
    cout << sizeof(Data) << endl;
}

int main()
{
    functionOne();
    functionTwo();    
} 

Output
functionOne()
The size of struct Data : 8
functionTwo()
The size of struct Data : 8

当我将“命名空间二”的代码更改为以下内容时:

namespace Two
{
    struct Data
    {
        char val;
        bool boolean;
    };
}

Output :

functionOne()
The size of struct Data : 8
functionTwo()
The size of struct Data : 2

我无法弄清楚编译器如何为结构分配内存。提前致谢。

【问题讨论】:

  • @CarlNorum 链接中的答案说明了 32 位架构。我可以知道对齐(通常)是在 64 位架构上完成的吗?
  • @mozart,你的例子可能是一样的。

标签: c++ namespaces


【解决方案1】:

这里的问题很可能是由于对齐要求。如果我没记错的话,结构是根据其成员的最大对齐要求对齐的。在您的结构的第一个版本中,您有int; char;。似乎在您的机器上 int 以 4 个字节对齐,因此编译器在 char 之后用额外的 3 个字节填充结构。在第二个版本中,您只有 bool; char;,它们的大小均为 1 字节,并且与 1 字节对齐(在您的机器上),因此编译器不需要填充任何内容,因此大小回落到 2。

我指定了“在您的机器上”,因为这可能因多种因素而异。

让我们做一个漂亮的图表!

// One::Data (version 1)
0              4              5                7
[int (size 4), char (size 1), padding (size 3)][...]
// Because of alignment restrictions on int, this needs a padding of 3 bytes

// Two::Data (version 1)
0              4              5                7
[int (size 4), bool (size 1), padding (size 3)][...]
// Because of alignment restrictions on int, this needs a padding of 3 bytes

// One::Data (version 2), no change

// Two::Data (version 2)
0               1             2
[char (size 1), bool (size 1)][...]
// No alignment restrictions, therefore no padding is required

【讨论】:

  • 第二个命名空间的改版,为什么要分配8个字节? 3个字节用作填充吗?
  • @mozart 我在看你的问题,修改后的版本是 2 号?
  • 对我的回答进行了澄清。
【解决方案2】:

关于编译器如何分配内存的官方回答是 “随心所欲”。有一些限制,但不是 许多。但是,在这种情况下,您所看到的 逻辑:许多类型有(或可能有)对齐限制, 并且必须放置在某个地址的倍数 价值。这些限制传播到任何班级 其中包含该类型的成员,否则,您 无法尊重班级成员的对齐方式。显然, 在您的机器上,bool 的大小为 1(并且 char 必须有 大小为 1),int 的大小为 4,也必须对齐 在 4 的地址倍数上。所以在 One::DataTwo::Data 中, 你有一个int,然后是charbool,然后是 足够的填充字节以构成结构的总大小 4 的倍数。(原则上,char/bool 和 填充可以按任何顺序混合,但实际上,每个 我见过的编译器将填充放在任何声明之后。)

因为boolchar 都没有任何对齐 限制,不需要在类中填充 每个只包含一个。

请注意,这取决于机器和编译器。在 一些机器(例如 Sun Sparc 或 IBM 大型机),访问 未对齐的值会导致硬件陷阱,编译器是 几乎需要对齐(并插入填充)。在英特尔上,在 另一方面,未对齐的访问将起作用,但有明显的 性能受到打击;编译器通常在此处强制对齐 (并且 Windows 和 Linux 二进制 API 都需要它),但是 编译器可能会忽略它,而一些非常早期的英特尔 编译器做到了,早在内存比现在更紧的时候 现在。 (这实际上是一个有趣的问题,它给出了 现代机器上的最高性能。如果你有一个大 具有您的结构之一的数组,由于额外的内存访问 to misalignment 可能会从缓存中解决,或者 即使是从内存读取管道,只需很少的额外成本, 而较小的对象可能会导致较少的缓存 未命中,从而获得更好的性能。但我没有采取任何措施, 所以我只是猜测。)

还有一点需要注意的是,标准要求该类 成员按顺序分配。从技术上讲,只有在没有 它们之间的访问说明符,但实际上,所有编译器 总是按顺序分配它们。因此,如果您有这样的课程:

struct T
{
    double d1;
    char c1;
    double d2;
    char c2;
};

它将(通常)大小为 32,其中:

struct T
{
    double d1;
    double d2;
    char c1;
    char c2;
};

只有 24 的大小。回到内存的时代 紧,我们经常关注这些事情,但现在 地方性有时是一个问题,也许这样做是值得的 再次:按变量大小的顺序声明变量,使用 首先是最大的。

【讨论】:

    猜你喜欢
    • 2016-02-08
    • 1970-01-01
    • 2023-04-06
    • 2019-04-15
    • 2023-01-12
    • 2016-01-27
    • 2014-07-24
    • 2021-10-08
    相关资源
    最近更新 更多