经典C语言面试题4:字节对齐的作用

   一、什么是字节对齐? 

    在现代计算机中,内存空间都是按照字节(byte)划分的。从理论上讲对任何类型的变量的访问可以从任何地址开始,但实际情况是,访问特定类型的变量的时候经常在特定的内存地址访问,这就需要各种类型的数据按照一定规则在空间上排列,而不是顺序地一个接一个地排放,这种所谓的规则就是字节对齐。这么长一段话的意思是说:字节对齐可以提升存取效率,也就是用空间换时间。

例如:

struct A
{
   char a;
   char reserved[3];//使用空间换时间
   int b; 
};


注:其中的reserved成员对于程序并没有意义,只是起到了填补空间达到字节对齐的目的。当然,即使不加这个成员,编译器也会自动为我们补齐,加上它只是起到显式提醒。

二、为什么需要字节对齐?

       因为各个硬件平台对存储空间的处理上有很大的不同,一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。

三、几个基本概念

1、基本数据类型的自身对齐值

      例如,char型数据的自身对齐值为1字节,short类型自身对齐值为2字节,int、float、long类型自身对齐值均为4字节,double类型自身对齐值均为8字节。(32位系统)

2、结构体或类的自身对齐值

     其成员中自身对齐值最大的那个值。

3、指定对齐值

      通过预编译指令 #pragma pack (value) 来指定的对齐值value。(注:取消自定义对齐值得指令为 #pragma pack ( ))

4、数据成员、结构体和类的有效对齐值

     其自身对齐值和指定对齐值中较小的那个值。

四、字节对齐的几个例子浅析

例1:设有如下两个结构体

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

那么上面两个结构体的大小是多少呢?

对于结构体A:a是char型数据,占用1字节内存;short型数据,占用2字节内存;int型数据,占用4字节内存。因此,结构体A的自身对齐值为4,sizeof(struct A) =8字节。由于结构体类型数据是按顺序存储结构一个接一个向后排列的,于是其存储方式为:


为了更加明显地表示“对齐”,我们可以将以上结构想象为以下的行排列:


对于结构体B:同理也是4字节对齐,但是sizeof(struct B) =12字节。


想象为以下的行排列:


例2:为结构体指定对齐值

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

对于结构体C:由于其自身对齐值为4字节(int b),而指定对齐值为2字节,因此该结构体的有效对齐值为较小的2字节,那么sizeof(struct C) = 8 字节。


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

对于结构体D:同理可知,由于其自身对齐值为4字节(int b),而指定对齐值为1字节,因此该结构体的有效对齐值为较小的1字节,那么sizeof(struct D) = 7 字节。

    

五、总结

由以上分析可知,字节对齐会造成空间上的浪费。 事实上,除了结构体之外,整个程序在给每个变量进行内存分配时都会遵循对齐机制,也都会产生内存空间的浪费。但我们要知道,这种浪费是值得的,因为它换来的是效率的提高。



评论 3 您还未登录,请先 登录 后发表或查看评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

喝橙汁的嗷大喵

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值