C/C++结构体字节对齐

稍微了解过C/C++的人,都会了解它们在创建一个结构体的时候,会进行字节对齐操做,因此每每比世界变量占用的字节数要多出一些,而如何减小内存占用,计算内存使用量,也是不少面试题里常常出现的题目。关于什么是字节对齐,如何实现字节对齐,哪些场合须要哪些场合不须要字节对齐,强烈推荐参考文章C语言字节对齐
可是稍微当咱们真的不想要字节对齐的时候,有没有办法取消字节对齐?答案是能够,就是在结构体声明当中,加上attribute ((packed))关键字,它能够作到让咱们的结构体,按照紧凑排列的方式,占用内存。css

#include <stdio.h>
#include <iostream>

using namespace std;

struct test1 {
    char c;
    int i;
};

struct test2 {
    char c;
    int i;
}__attribute__((__packed__));

int main()
{
    cout << "size of test1:" << sizeof(struct test1) << endl;
    cout << "size of test2:" << sizeof(struct test2) << endl;
}

输出结果:ios

size of test1:8
size of test2:5

下面的示例能更清楚地说明这种现象:web

#include<stdio.h>
typedef struct{
     char  c1;
    short s; 
    char  c2; 
    int   i;
}T_FOO;
int main(void){  
    T_FOO a; 
    printf("c1:%x\ns:%x\nc2:%x\ni:%x\n",&a.c1,&a.s,&a.c2,&a.i);
    printf("c1 -> %d\ts -> %d\tc2 -> %d\ti -> %d\n", 
          (unsigned int)(void *)&a.c1 - (unsigned int)(void *)&a,
          (unsigned int)(void *)&a.s  - (unsigned int)(void *)&a, 
          (unsigned int)(void *)&a.c2 - (unsigned int)(void *)&a, 
          (unsigned int)(void *)&a.i  - (unsigned int)(void *)&a); 
    return 0;
}

输出结果:面试

c1:60ff38
s:60ff3a
c2:60ff3c
i:60ff40
c1 -> 0 s -> 2  c2 -> 4 i -> 8

上例中,结构体中变量默认按照最长的int型变量 i 即4字节对齐,因此char型变量c1实际上只有1个字节,可是后面的short型变量s并无立刻紧挨着c1排列,而是为了4字节对齐,中间空了一个字节内存,后面的c2同理也是如此。svg

#include<stdio.h>
typedef struct {
    char  c1;
    short s;
    char  c2;
    int   i;
}T_FOO;
int main(void) {
    T_FOO a;
    a.c1 = 'a';
    a.s = 100;
    a.c2 = 'b';
    a.i = 1000;
    printf("size of T_FOO a:%d\n ", sizeof(a));
    printf("c1: %c\n", a.c1);
    printf("behind c1: %x\n", *(&a.c1 + 1));
    printf("s: %d\n", a.s);
    printf("c2: %c\n", a.c2);
    printf("behind c2: %x\t%x\t%x\t\n", *(&a.c2 + 1), *(&a.c2 + 2), *(&a.c2 + 3));
    printf("i: %d\n", *((int *)(&a.c2 + 4)));
    return 0;
}
size of T_FOO a:12
 c1: a
behind c1: 30
s: 100
c2: b
behind c2: 30   40      0
i: 1000

另外,还有以下的一种方式:
· __attribute((aligned (n))),让所做用的结构成员对齐在n字节天然边界上。若是结构中有成员的长度大于n,则按照最大成员的长度来对齐。
· attribute ((packed)),取消结构在编译过程当中的优化对齐,按照实际占用字节数进行对齐。优化

例1
struct test
{
char x1;
short x2;
float x3;
char x4;
};ui

因为编译器默认状况下会对这个struct做天然边界(有人说“天然对界”我以为边界更顺口)对齐,结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,所以,编译器在x2和x1之间填充了一个空字节。结构的第三个成员x3和第四个成员x4刚好落在其天然边界地址上,在它们前面不须要额外的填充字节。在test结构中,成员x3要求4字节对界,是该结构全部成员中要求的最大边界单元,于是test结构的天然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间为12字节。spa

例2.net

pragma pack(1) //让编译器对这个结构做1字节对齐

struct test
{
char x1;
short x2;
float x3;
char x4;
};
pragma pack() //取消1字节对齐,恢复为默认4字节对齐
这时候sizeof(struct test)的值为8。code

例3

define GNUC_PACKED attribute((packed))

struct PACKED test
{
char x1;
short x2;
float x3;
char x4;
}GNUC_PACKED;

这时候sizeof(struct test)的值仍为8。

#include <stdio.h>
main()
{
struct A {
    int a;
    char b;
    short c;
};

struct B {
    char b;
    int a;
    short c;
};

#pragma pack (2) /*指定按2字节对齐*/
struct C {
    char b;
    int a;
    short c;
};
#pragma pack () /*取消指定对齐,恢复缺省对齐*/



#pragma pack (1) /*指定按1字节对齐*/
struct D {
    char b;
    int a;
    short c;
};
#pragma pack ()/*取消指定对齐,恢复缺省对齐*/

int s1=sizeof(struct A);
int s2=sizeof(struct B);
int s3=sizeof(struct C);
int s4=sizeof(struct D);
printf("%d\n",s1);
printf("%d\n",s2);
printf("%d\n",s3);
printf("%d\n",s4);
}

输出

8
12
8
7