结构体对齐

linux 32平台下默认对齐方式为:

  1. char 按照字节对齐2. short 按照2字节对齐
  2. int,long等其他基本类型按照4字节对齐
  3. 为了让结构体数组中的每一个结构体内部元素都保持对齐,编译器会在结构体的末尾插入gap以满足结构体内部元素的对齐要求。结构体的地址对齐按照结构体中包含的最大字节数元素对齐,以满足结构体数组的对齐要求。
    或者根据原理:

    pack pragma
    pack pragma设置了struct、union或class中各成员的对齐方式,结构成员对齐指的是成员相对于起始地址的偏移量。该指令基本用法如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #pragma pack(n)  
    ```
    它指定了结构成员按n(124816)(alignment must be a small power of 2)字节对齐,如果未指定n,则恢复成默认值。需要注意的是,它并不是指结构体中的每个成员都要按n对齐,而是 按照每个成员的大小和n相比较小的值对齐。下面引用MSDN中C++ Preprocessor Reference部分关于pack指令的说明:
    n (optional) 
    Specifies the value, in bytes, to be used for packing. The default value for n is 8. Valid values are 1, 2, 4, 8, and 16. The alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.
    即成员member的对齐值
    align of member = min( pack setting value, sizeof(member type) )
    >
    这里的pack是编译器结构体对齐的字节数,默认是4字节,可以通过#pargma pack(n)
    进行调整(#pargma unpack() 回复到原来),boxsize 也就是每个成员对齐的盒子大小,
    计算时成员所占内存大小必须是这个boxsize的整数倍,
    `box_size=min{pack,max{sizeof(member type)} } `注意这里的sizeof(memeber type) 是成员的基本类型比如:char a[10],应该是sizeof(char) 而不是sizeof(a[10])


    编译器每次只取一个盒子大小的内存,如果当前盒子不够又会在再取一个盒子的大小:
    ```c
    struct A
    {
    int a;
    int b;
    short s;
    char c;
    };

    sizeof(A)=12

    分析:

    1
    2
    3
    box_size=min{pack(4),max(sizeof(member))}
    =min{4,4}
    =4

    因为编译器先取一个盒子放a,刚好用完已取内存接着再拿一个盒子大小的内存放b也刚好用完,接着再取一个,发现存放s之后还有2个字节,接着与c大小比较,结果也能够存储c。所以size=12。所以我们应该尽量将不能是box_size大小的成员放在一起,以节省内存。
    上面的例子如果调换一下b和s的位置那么sizeof=16

  4. 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    struct ch{
    char c;
    }; //sizeof ch = 1
    printf("Sizeof ch =%d\n",sizeof (ch));

    struct ch2{
    char c;
    char cc;
    };//sizeof ch2 = 2
    printf("Sizeof ch2 =%d\n",sizeof (ch2));

    struct size{
    char c;
    short s;
    }; //sizeof size = 4
    printf("Sizeof size1=%d\n",sizeof (size));
    struct size{
    char c;
    char cc;
    short s;
    };//sizeof size = 4
    printf("Sizeof size2=%d\n",sizeof (size));
    struct size{
    char c;
    short s;
    char cc;
    };//sizeof size = 6
    printf("Sizeof size3=%d\n",sizeof (size));
    struct size{
    char c;
    char cc;
    int i;
    };//sizeof size = 8
    printf("Sizeof size4 =%d\n",sizeof (size));
    struct size{
    char c;
    int i;
    char cc;
    }; //sizeof size = 12
    printf("Sizeof size5=%d\n",sizeof (size));

    struct size{
    char c;
    char cc;
    int i;
    struct ch ich;
    };//sizeof size = 12
    printf("Sizeof size6=%d\n",sizeof (size));

    struct size{
    char c;
    char cc;
    struct ch ich;
    int i;
    };sizeof size = 8
    printf("Sizeof size7=%d\n",sizeof (size));

    运行结果:
    Sizeof ch =1
    Sizeof ch2 =2
    Sizeof size1=4
    Sizeof size2=4
    Sizeof size3=6
    Sizeof size4 =8
    Sizeof size5=12
    Sizeof size6=12
    Sizeof size7=8

当结构体中出现结构体类型的数据成员是,不会将嵌套的结构体类型的整体长度参与到对齐计算中,而是以嵌套定义的结构体锁使用的对齐值进行对齐。
eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct tagOne
{
char cChar;
char cArray[4];
short sShort;
};
struct tagTwo
{
int nInt;
struct tagOne to;
};
虽然tagOne占据量8字节大小,但由于其对齐值为min{pack,max{sizeof(member type)}} = 2
所以tagTwo的对齐值应该为 min{pack,max{sizeofmember type}} = 4
坚持原创技术分享,您的支持奖鼓励我继续创作!