C++ 字节对齐

 

C++ 字节对齐

1. 缘起

    来自BBS上的面试题目,struct{int a; char b;}的大小是多少?答案是8。上网看了下,是字节对齐。

2. 字节对齐的基本规则

    首先,每种类型的变量的默认对齐长度都是自己的变量长度,比如:char占一个字节,那么对齐长度就是一个字节,int占四个字节,对齐长度就是四个字节,double占八个字节,对齐长度就是8。int的对齐长度为4的实际意义是,int变量必须存储在四的倍数的地址上。
    那么对于struct{char b; int a},其长度是8,因为b虽然只占用1个字节,但是a必须从4的倍数开始存储,因此b后面的3个字节都废掉了。因此一共需要8个字节才能把b和a存下来。
    那么对于struct{int a; char b},其长度还是8!晕菜了!原因如下:
    字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
   1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
   2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
   3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
   规则1是控制结构体变量的首地址的,与结构体变量的长度没关系。
   规则2是控制结构体内每个变量的相对地址的,与结构体变量的长度有关系。
   规则3是控制结构体总体长度的,与结构体变量的长度有关系。
   正是由于第三条规则,结构体的长度必须是其最长的变量长度的整数倍,因此在上面的例子中,必须是4的整数倍,因此,是8。
   如果结构体里面嵌套结构体就要注意了,结构体变量的起始地址只是其内部最宽的基本类型的整数倍,而非结构体自身的整数倍,外面结构体的长度,也仅仅是里面最宽的基本类型的长度倍数。
   比如: 

struct  S1 {
  
char  c;   //  1个字节
   int  i;    //  前面空3个字节,占用4个字节
};  //  刚好8个字节,是4的倍数 
struct  S2 { 
  
char  c1;  //  1个字节
  S1 s;   //  前面空3个字节,而不是空7个字节,占用8个字节
   char  c2;  //  占用1个字节 
};  //  一共13个字节,要成为4的倍数,后面增加3个字节,成为16个字节

3. 字节对齐的原因

   ·效率原因,某些平台每次都是从偶地址读数据,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。

4. 字节对齐的隐患

   ·不合理设置变量定义的顺序,可能浪费内存   

struct  S1 {  //  长度为16
     char  a;
    
int  b;
    
char  c;
    
int  d;
}
struct  S2 {  //  长度为12
     char  a;
    
char  c;
    
int  b;
    
int  d;   
}

   ·更多的是在对地址运算时,没有考虑的字节对齐问题

char  a;
int  b;
int   * pb  =   & a + 1 // 这样a的地址加1,并不是b的地址,实际上,这行代码,在编译时就出现了ERROR,因为不能把char *的地址赋值给int *的变量

5. 参考文章

结构体字节对齐问题  http://blogold.chinaunix.net/u1/49467/showart_424793.html
字节的对齐原理 http://zhengyueyatou.blog.sohu.com/64814717.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值