编译器如何为此结构分配内存?

时间:2013-07-21 16:12:22

标签: c++ namespaces

我试图使用命名空间和结构&遇到了问题。

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'的代码更改为以下内容时:

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

Output :

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

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

2 个答案:

答案 0 :(得分:5)

这里的问题很可能是由于对齐要求。如果我没有弄错的话,结构会根据其成员的最大对齐要求进行对齐。在结构的第一个版本中,您有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

答案 1 :(得分:2)

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

由于boolchar都没有任何对齐方式 限制,没有必要在类中填充 只包含其中一个。

请注意,这取决于机器和编译器。上 一些机器(例如Sun Sparc或IBM大型机)访问 未对齐的值将导致硬件陷阱,编译器是 几乎需要对齐(并插入填充)。在英特尔,在 另一方面,错位访问将起作用,但有明显的 表现打击;编译器通常强制对齐 (以及Windows和Linux二进制API都需要它),但是a 编译器可以想象它会忽略它,而一些非常早期的英特尔 当内存比它更紧凑时,编译器会这样做 现在。 (这实际上是一个有趣的问题 在现代机器上的最佳性能。如果你有一个大的 数组与您的一个结构,额外的内存访问到期 错位可能会从缓存中解决,或者 甚至从内存读取管道,只需很少的额外费用, 而较小尺寸的物体可能导致较少的缓存 错过了,从而提高了性能。但我没有采取措施, 所以我只是在猜测。)

需要注意的另一点是标准要求该类 成员按顺序分配。从技术上讲,只有在没有的情况下 它们之间的访问说明符,但在实践中,所有编译器 总是按顺序分配它们。所以如果你有一个类:

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

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

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

只有24的大小。回到记忆的日子 我们经常关注这类事情,但现在这样 地方有时是一个问题,也许它会付出代价 再次:按照大小的顺序声明变量 最重要的是。