C/C++结构体字节对齐
稍微了解过C/C++的人,都会了解它们在建立一个结构体的时候,会进行字节对齐操作,所以往往比世界变量占用的字节数要多出一些,而如何减少内存占用,计算内存使用量,也是很多面试题里经常出现的题目。关于什么是字节对齐,如何实现字节对齐,哪些场合需要哪些场合不需要字节对齐,强烈推荐参考文章C语言字节对齐
但是稍微当我们真的不想要字节对齐的时候,有没有办法取消字节对齐?答案是可以,就是在结构体声明当中,加上attribute ((packed))关键字,它可以做到让我们的结构体,按照紧凑排列的方式,占用内存。
#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;
}
输出结果:
size of test1:8
size of test2:5
下面的示例能更清楚地说明这种现象:
#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同理也是如此。
#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;
};
由于编译器默认情况下会对这个struct作自然边界(有人说“自然对界”我觉得边界更顺口)对齐,结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间填充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然边界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4字节对界,是该结构所有成员中要求的最大边界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间为12字节。
例2
pragma pack(1) //让编译器对这个结构作1字节对齐
struct test
{
char x1;
short x2;
float x3;
char x4;
};
pragma pack() //取消1字节对齐,恢复为默认4字节对齐
这时候sizeof(struct test)的值为8。
例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
还没有评论,来说两句吧...