一个例子彻底理解C结构体内存对齐问题

前言

   俗话说的好,磨刀不误砍柴工,对于C结构体的相关知识还是要先了解清楚,当然如果已经了然于胸,此处可忽略
咱就直奔主题,看例子急速掌握。小白的我还是要先从基本的开始(Ps:白了很多次,还是白,没办法,太笨了)

基础一:为啥要内存对齐?

    对于这个问题,之前小白没有太深的理解,后来大神的代码看多了,项目遇到坑以后(果然疼了才能记得住)才
 幡然醒悟,要好好学习。通用说法:就是为了提高代码效率,利于平台移植,空间换时间;对于小白而言,最主要
 的是节约空间,提高空间利用率,毕竟小白的设备内存很金贵。

基础二:内存对齐三原则(没有#pragma pack宏定义下)

	1)、首地址0为结构体内第一个元素位置
 	2)、每个结构体内元素的首地址是自身基本数据类型大小的整数倍
 	3)、结构体的总大小,是其所有元素所含最大类型数的整数倍

基础三:内存对齐三步走

第一步:确认最大对齐数,三种情况取其中较小值
        1)、预编译设置#pragma pack(8),取值只能是 0,1,2,4,8,16
        2)、结构体中最大成员基本数据类型,比如:char,int,double 最大是8
        3)、设备默认值 WIN  vs  qt  默认8字节对齐,Linux 32位 默认4字节对齐,64位默认8字节对齐
             最大对齐数可以理解为:每次分配空间给数据时的最大值
 第二步:给每个数据分配空间,从0地址开始,每次分配给数据的空间起始地址(相对于0地址)都必须是数据基本
        类型大小与最大对齐数中较小值的整数倍
 第三步:结构体的总大小必须是最大对齐数的整数倍

注意点:

 1)、对于嵌套的结构体,其空间起始地址必须是嵌套结构体的最大对齐数
 2)、对于联合体,他们共用一个空间

废话不多说,直接上例子

/*
  结构体A
  第一步:预编译设置为8 ,成员最大基本数据类型为:double 8,(设备Linux 32位)默认 4,故最最对齐数取 4
  第二步:依次按数据分配
          1)char  1< 4  取对齐数 1  起始地址 0    是1的整数倍   0+1=1
          2)int   4= 4  取对齐数 4  当前地址是1   不是4的整数倍,故补齐,分配地址从4开始 4+4=8;
          3)double 8>4   取对齐数 4  当前地址是8   是4的整数倍, 8+8=16;
          4)short  2<4   取对齐数 2  当前地址是16  是2的整数倍, 16+2=18;
  第三步:当前结构体总大小为18,不是最大对齐数4的整数倍,故补齐,结构体总大小为:20
 */
#pragma pack(8)   
typedef struct _A
{
   char    a;
   int     b;
   double  c;
   short   e;
   //float   d;
}A;
#pragma pack()
/*
  共用体B
  取共用最大空间值 int 4
 */
#pragma pack(8)
typedef union _B
{
    char f:1;
    int  g:8;
    int  h;
}B;
#pragma pack()
/*
  结构体C
  第一步:预编译设置为8 ,成员最大基本数据类型为:double 8,(设备Linux 32位)默认 4,故最大对齐数取 4
  第二步:依次按数据分配
          1)char  1< 4  取对齐数 1      起始地址 0    是1的整数倍   0+1=1
          2)结构体A  最大对齐数为 4=4   当前地址是1   不是4的整数倍,故补齐,分配地址从4开始;
             结构体内依次为:4+1=5;(与结构体A取法一致)
                            8+4=12;
                            12+8=20;
                            20+2=22;
                           不足补齐 24
          3)char 1<4  取对齐数 1  当前地址是24  是1的整数倍, 24+2=26;
          4)共用体B   最大数据长度为4,对齐数为4 ,当前地址是26   不是4的整数倍,故补齐28+4=32;
          5)short 2<4 取对齐数 2  当前地址是32  是2的整数倍, 32+2=34;
  第三步:当前结构体大小为34,不是最大对齐数4的整数倍,故补齐,结构体大小为:36
 */
#pragma pack(8)
typedef struct _C
{
	char   C_a;
	A     C_b;
	char  C_e[2];
	B     C_c;
	short C_d;
}C;
#pragma pack()

int main(int argc, char const *argv[])
{
	printf("sizeof (double)       =%d\n",sizeof(double));
	printf("sizeof (float)        =%d\n",sizeof(float));
	printf("sizeof (short)        =%d\n",sizeof(short));
	printf("sizeof (A)     20     =%d\n",sizeof(A));
	printf("sizeof (B)     4      =%d\n",sizeof(B));
	printf("sizeof (C)     36     =%d\n",sizeof(C));
	return 0;
}

结果:

sizeof (double)       =8
sizeof (float)        =4
sizeof (short)        =2
sizeof (A)     20     =20
sizeof (B)     4      =4
sizeof (C)     36     =36
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值