黑马程序员——C语言日志——关于结构体内存对齐

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

1、什么是结构体的内存对齐?

我们先看一个结构体


 char   Class;
 int   num;
 short   ID;
 };
我们在VC6.c环境下输出sizeof(Std)=12;它不是简单的将成员变量类型所占字节数相加得7,而是根据成员变量中最大数据类型的宽度int来分配内存,分配三个int宽度的内存,三个成员变量各占4个字
节的内存,所以是3*4=12。
再看一个例子,把结构体Std中成员变量调一下顺序:

struct Std1{
 int   num;
 char   Class;
 short   ID;
 };
这样一来,输出输出sizeof(Std1)=8,内存按照成员变量中最大数据类型的宽度来分配两个int宽度内存,num变量占一个4字节内存,Class和ID占一个4字节内存(具体是怎么分配内存,在下面第3问中会详细介绍)。这就是所谓的结构体内存对齐。
2、为什么要进行结构体内存对齐?
我们再定义一个结构体Std3

struct Std3{
 char   Class;
 int   num;
 short   ID;
 short   name;
 };
我们在程序中经常要改变和读取成员变量中的值,程序在执行过程中处理器会先找到这个成员变量的地址,然后才能操作改地址中存储的数据,如果处理器一次能操作8个字节的数据,那么我们现在要访问成员变量name中的数据,处理器会怎么操作呢?
(1):没有内存对齐的情况。没有内存对齐的话,sizeof(Std3)=1+4+2+2=9;name的两个字节中的第一个字节在前8个字节中,第二个字节在后8个字节中,所以处理器访问name需要先访问前8个字节,然后取出其中的最后一个字节的数据,然后再访问后8个字节,然后取出其中的第一个字节,这样处理器总共寻址访问了两次。
(2):有内存对齐的情况。经过了内存的对齐,sizeof(Std3)=4+4+4=12;name中的两个字节都在后8个字节中,那么处理器访问name只需要访问一次,将后8个字节的数据取出,再分离出name。显然,这种情况下,处理器的效率会有很大提高,以空间换时间,虽然这样浪费了些许内存,但是信息时代时间比空间更重要!
3、怎么进行结构体内存对齐?
先介绍一下对齐模数的概念。计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数。
下面来介绍一下结构体中成员怎么进行对齐的。
(1)定义结构体之后,编译器首先来判断这个结构体中成员变量中类型最大宽度为多少,然后寻找内存地址能被该基本数据类型所整除的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。但是这个最宽大小不能超过对齐模数的默认值(win32下VC6.0中k的默认值为8,GNU GCC的默认值为4,这个默认值也可以在预编译#pragma  pack(n)中更改,n的取值为,1,2,4,8,在这里不做详细介绍)。
(2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节.如:

struct Std3{
 char   Class;  //偏移为0,占1(自身大小)+3(填充大小)=4字节
 int   num;    //偏移为4,是4的整数倍,占4(自身大小)字节
 short   ID;   //偏移为8,是2的整数倍,占2(自身大小)字节
 short   name;//偏移为10,是2的整数倍,占2(自身大小)字节
 };
所以sizeof(Std3)=4+4+4=12;
再如结构体:

struct A{
        short a;  //偏移为0,占2(自身大小)+2(填充大小)=4字节
	float b;  //偏移为4,是4的整数倍,占4(自身大小)字节
	char c;   //偏移为8,是1的整数倍,占1(自身大小)+7(填充大小)=8字节
	double d; //偏移为16,是8的整数倍,占8(自身大小)字节

};
所以sizeof(A)=4+4+8+8=24;正是因为这个结构体,让我萌生了写这篇博客的念头,因为最近在看黑马的C语言教学视频,其中关于结构体对齐的那一节课中,老师就举了这么一个结构体例子,测量结构体大小,运行结果为24 ,我之前一直认为应该是16,于是乎便挖出了这么些个道道来,整合前辈大神的看法,再加上我的理解,汇总成这一篇博客。
(3)继续,结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节。如:

struct B{
        short a;  //偏移为0,占2(自身大小)+2(填充大小)=4字节
	float b;  //偏移为4,占4(自身大小)字节
	short C;   //偏移为8,占2(自身大小)+2(最末一个成员之后加上填充字节)=4字节
	
};

所以sizeof(A)=4+4+4=12,是4的整数倍。
好了,终于写完了,不知不觉22点多了,困意开始泛滥了,寂静的晚上,莫名的伤感袭来!





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值