结构对齐填充,最大填充大小以及结构成员的顺序

时间:2016-05-21 08:28:29

标签: c++ c struct padding memory-alignment

我一直在学习结构数据填充,因为我发现我的sizeof()运算符没有返回我的预期。根据我观察到的模式,它将结构成员与最大的数据类型对齐。例如......

struct MyStruct1
{
    char a;     // 1 byte
    char b;     // 1 byte
    char c;     // 1 byte
    char d;     // 1 byte
    char e;     // 1 byte
                // Total 5 Bytes

    //Total size of struct = 5 (no padding)
};

struct MyStruct2
{
    char a;     // 1 byte
    char b;     // 1 byte
    char c;     // 1 byte
    char d;     // 1 byte
    char e;     // 1 byte
    short f;    // 2 bytes
                // Total 7 Bytes

    //Total size of struct = 8 (1 byte of padding between char e and short f
};

struct MyStruct3
{
    char a;         // 1 byte
    char b;         // 1 byte
    char c;         // 1 byte
    char d;         // 1 byte
    char e;         // 1 byte
    int f;          // 4 bytes
                    // Total 9 bytes

    //Total size of struct = 12 (3 bytes of padding between char e and int f
};

但是,如果将最后一个成员设为8字节数据类型(例如long long),它仍然只添加3个字节的填充,从而形成一个四字节对齐的结构。但是,如果我构建在64位模式下,它实际上会对齐8个字节(最大的数据类型)。我的第一个问题是,我错误地说它将成员与最大的数据类型对齐?对于64位构建,此语句似乎是正确的,但在32位构建中仅适用于最多4字节数据类型。这与本地词#39;有关吗? CPU的大小?还是程序本身?

我的第二个问题是,以下是否会浪费整个空间和糟糕的编程?

struct MyBadStruct
{
    char a;             // 1 byte
    unsigned int b;     // 4 bytes
    UINT8 c;            // 1 byte
    long d;             // 4 bytes
    UCHAR e;            // 1 byte
    char* f;            // 4 bytes 
    char g;             // 1 byte
                        // Total of 16 bytes

    //Total size of struct = 28 bytes (12 bytes of padding, wasted)
};

感谢。

3 个答案:

答案 0 :(得分:3)

以下所有内容均取决于实现。不要依赖于程序的正确性(但无论如何都要利用它来调试或提高性能)。

通常,每种数据类型都有一个首选对齐方式。这永远不会大于类型的大小,但它可以更小。

在32位模式下编译时,编译器似乎在32位边界上对齐64位整数,但在64位模式下在64位边界上对齐。

关于MyBadStruct的问题:一般来说,编写简单易懂的代码;如果你知道(通过测量)你有问题,只做其他事情。话虽如此,如果按大小(最大的第一个)对成员变量进行排序,则可以最小化填充空间。

答案 1 :(得分:1)

如何填充,不是标准的一部分。所以它可以在不同的系统和编译器上以不同的方式完成。通常这样做是为了使变量在那里大小对齐,即大小= 1 - >。没有对齐,大小= 2 - > 2字节对齐,大小= 4 - > 4字节对齐等。对于size = 8,通常对齐4或8个字节。它自身的结构通常是4或8字节对齐。但是 - 只是重复 - 它取决于系统/编译器。

在你的情况下,它似乎遵循上面的模式。

所以

char a;
int  b;

将3字节填充为4字节对齐int。

char a1;
int  b1;
char a2;
int  b2;
char a3;
int  b3;
char a4;
int  b4;

将以32字节结束(再次以4字节对齐int)。

但是

int  b1;
int  b2;
int  b3;
int  b4;
char a1;
char a2;
char a3;
char a4;

只有20,因为int已经对齐。

因此,如果记忆很重要,那就把最大的成员放在首位。

但是,如果内存不重要(例如因为结构没有被使用那么多),最好将事物按逻辑顺序保存,以便代码易于为人类阅读。

答案 2 :(得分:1)

通常,减少编译器插入的填充量的最佳方法是将结构内部的数据成员从最大到最小排序:

struct MyNotSOBadStruct
{
    long d;             // 4 bytes
    char* f;            // 4 bytes
    unsigned int b;     // 4 bytes
    char a;             // 1 byte
    UINT8 c;            // 1 byte
    UCHAR e;            // 1 byte
    char g;             // 1 byte
                        // Total of 16 bytes


};

大小可能因32位与64位操作系统而异,因为指针的大小会改变

实时版:http://coliru.stacked-crooked.com/a/aee33c64192f2fe0

我得到尺寸= 24