关于字节对齐

1、概念

        字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,一个字节等于8位二进制数,在UTF-8编码中,一个英文字符等于一个字节。字节按照一定规则在空间上排列就是字节对齐。

2、理由

        需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求非常严格,比如sparc系统,如果取未对齐的数据会发生错误。

3、理解

        字节对齐的几大原则:

  1. 数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。
  2. 结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储。)
  3. 联合体作为成员:按照其包含的长度最大的数据类型对齐。
  4. 收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍。不足的要补齐。
        由于在x86下,GCC默认按4字节对齐,比如:
struct stu{
   char sex;
   int length;
   char name[10];
  };
  struct stu my_stu;
它会在 sex 后面填充三个字节,使其与 int 长度对齐,name 后面填充两个字节使整个结构体对齐,使得 sizeof(my_stu) 为 20(4 的倍数),而不是15。

4、例子

#include <iostream>
using namespace std;

//#pragma pack(1)

typedef struct bb
{
	int id;             //[0]....[3]
	double weight;      //[8].....[15]      原则1
	float height;      //[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3
}BB;

typedef struct aa
{
	char name[2];     //[0],[1]
	int  id;         //[4]...[7]          原则1

	double score;     //[8]....[15]    
	short grade;    //[16],[17]        
	BB b;             //[24]......[47]          原则2
}AA;

int main()
{
	AA a;
	cout << sizeof(a) << " " << sizeof(BB) << endl;
	system("pause");
	return 0;
}
结果是:48 24
        对于 BB:4+[4]+8+4+[4]=24,其中 [] 表示补齐的字节数。
        对于 a :2+[2]+4+8+2+[6]+24=48,同样地,[] 表示补齐的字节数。

5、#pragma pack()

        再讲讲#pragma pack()。
        在上述代码前加一句 #pragma pack(1),则输出的结果就变得很不一样:32 16
        对于 BB:4+8+4=16
        对于 a:2+4+8+2+16=32
所有的补齐字节都消失了,这就相当于没有内存对齐的情况。#pragma pack(1) 就是告诉编译器:所有的对齐都按照1的整数倍对齐,换句话说就是没有对齐规则。
        在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
  • 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
  • 使用伪指令#pragma pack (),取消自定义字节对齐方式。

6、__attribute__选项

        我们可以按照自己设定的对齐大小来编译程序,GNU使用__attribute__选项来设置,比如我们想让刚才的结构按一字节对齐,我们可以这样定义结构体:
struct stu{
   char sex;
   int length;
   char name[10];
  }__attribute__ ((aligned (1))); 
struct stu my_stu;
则sizeof(my_stu)可以得到大小为15。上面的定义等同于:
struct stu{
   char sex;
   int length;
   char name[10];
  }__attribute__ ((packed)); 
struct stu my_stu;
__attribute__((packed))得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐。


参考链接:
1、http://blog.csdn.net/21aspnet/article/details/6729724/
2、http://blog.csdn.net/hairetz/article/details/4084088




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在结构体嵌套中,字节对齐是一个需要注意的问题。字节对齐是为了提高内存访问的效率和处理器的性能。当结构体中包含多个成员时,编译器会根据特定的对齐规则在成员之间插入额外的字节,以确保结构体成员按照特定的字节对齐方式进行存储。 在结构体嵌套中,需要特别注意的是: 1. 结构体成员的字节对齐方式:结构体成员的字节对齐方式可能会影响嵌套结构体的对齐。一般来说,结构体成员的对齐方式与其类型有关,比如 `int` 类型一般按照 4 字节对齐,而 `double` 类型一般按照 8 字节对齐。结构体成员的对齐方式可能会导致整个结构体的字节对齐方式发生变化。 2. 结构体嵌套的字节对齐方式:当一个结构体嵌套在另一个结构体中时,编译器会尽量保持嵌套结构体的对齐方式与其在外部结构体中的位置一致。但是,如果外部结构体的字节对齐方式要求更严格,编译器可能会在嵌套结构体之间插入额外的填充字节。 为了避免字节对齐带来的问题,我们可以使用编译器提供的对齐指令或者特性来控制结构体的对齐方式,以确保结构体的成员按照预期进行布局。 在 C 语言中,可以使用 `#pragma pack` 指令来设置字节对齐方式。例如,`#pragma pack(1)` 将设置字节对齐为 1 字节,可以避免额外的填充字节。但是需要注意,使用 `#pragma pack` 指令可能会影响性能和存储效率,因此需要谨慎使用。 另外,在一些编译器中,也提供了特定的特性或者选项来控制结构体的对齐方式,可以根据具体的编译器和平台文档进行查阅和使用。 综上所述,在结构体嵌套中,我们需要注意结构体成员的字节对齐方式,并且可以使用编译器提供的对齐指令或者特性来控制结构体的对齐方式,以避免字节对齐带来的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值