在说明对齐问题之前请看下面代码:
-
#include "stdio.h"
-
-
void main(int argc, char *argv)
-
{
-
-
struct A
-
{
-
int a;
-
char b;
-
short c;
-
};
-
-
struct B
-
{
-
char b;
-
int a;
-
short c;
-
};
-
-
printf("sizeof(int)=%d sizeof(char)=%d sizeof(short)=%d\n",sizeof(int),sizeof(char),sizeof(short));
-
-
printf("sizeof(A) =%d sizeof(B)=%dn",sizeof(struct A),sizeof(struct B));
-
}
在运行代码之前,请思考下输出值应该是多少?如果你的答案是8 12,那么恭喜你!
那么两个看似相同的结构体,大小差异为什么会这么大?这都是归因于计算机的字节对齐。
所谓字节对齐:
计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放。
下面引入几个关于对其的概念:
1.数据类型的字对齐:对于char 自对其为1字节,对于short 自对齐值为2字节,对于int float double自对齐值为4字节。
2.结构体(位域)的自对齐值为其成员中自对齐最大的值。
所谓自对齐值即 变量的起始地址%自对齐值==0.
下面分析下struct B:
假定结构体的开始地址为0x00,那么b的存储空间为0x00 ,0x00 %1==0,a的存储地址为多少呢?由于a需自对齐,必须使a的起始%4==0,同时必须紧靠b,容易得出a的起始地址为0x04。0x01-——0x03为结构体的填充字节,c的起始地址为0x08。根据上面的推断,那B的长度应该是10为什么会是12呢?请看概念2,结构体类型也有自对齐,是成员中自对齐的最大值既4。假如存在结构体B数组,为了保证第二个元素的自对齐,那么第一个元素的长度必须是12,既sizeof(struct B)==12.
既然系统有默认的对齐方式,那么对齐的方式在C语言中是否可以改变呢?答案是肯定的:
3.可以用#pragma pack(value)改变对齐的值。
4.当使用了#pragma pack(value)时,数据成员,结构体的对齐值为自对齐值和指定对齐值中的较小值
请看实列:
-
#include "stdio.h"
-
-
void main(int argc, char *argv)
-
{
-
struct A
-
{
-
int a;
-
char b;
-
short c;
-
};
-
-
struct B
-
{
-
char b;
-
int a;
-
short c;
-
};
-
-
printf("sizeof(A) =%d sizeof(B)=%d\n",sizeof(struct A),sizeof(struct B));
-
-
#pragma pack (2) //指定为2字节对齐
-
struct c
-
{
-
char b;
-
int a;
-
short c;
-
};
-
printf("sizeof(C)=%d\n",sizeof(struct c));
-
#pragma pack () //取消2字节对齐
-
-
#pragma pack (1) //指定1字节对齐
-
struct D
-
{
-
char b;
-
int a;
-
short c;
-
};
-
printf("sizeof(D)=%d\n",sizeof(struct D));
-
#pragma pack () //取消指定的1字节对齐
-
-
}
思考下C D的长度应该分别为多少?
下面分析下 C,D结构体的长度:由于自定了对齐方式为2,根据规则4 char int short 的有效自对齐值分别为1 2 2,结构体的有效自对齐由4变为2,故假如C的起始地址为0x00,b的地址为0x00 a的起始地址为0x02,c的起始地址为0x06.
由于D指定对齐长度为1,那么char int short 以及结构体的有效自对齐都变为1,当b的起始地址为0x00时,a的地址为0x01,c的起始地址为0x05。
阅读(293) | 评论(0) | 转发(0) |