字节对齐 订阅
字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,一个字节等于8位二进制数,在UTF-8编码中,一个英文字符等于一个字节。字节按照一定规则在空间上排列就是字节对齐。 展开全文
字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位,一个字节等于8位二进制数,在UTF-8编码中,一个英文字符等于一个字节。字节按照一定规则在空间上排列就是字节对齐。
信息
外文名
Byte aligned
拼    音
zi jie dui qi
相关领域
计算机信息技术
释    义
字节按照一定规则在空间上排列
中文名
字节对齐
性    质
一种计量单位
字节对齐解释
现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
收起全文
精华内容
下载资源
问答
  • 什么是字节对齐,为什么要对齐 现代计算机中内存空间都是按照BYTE划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种...
  • 本文介绍了字节对齐的原因、作用以及什么时候需要对齐。
  • 随便google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则
  • 结构体字节对齐规则

    2018-01-29 11:17:59
    结构体字节对齐规则,主要是介绍结构体字节对齐规则,内容有点长,但是很全面.
  • 什么是字节对齐,为什么要对齐?  现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要...
  • 这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式。 #pragma pack (n) 作用:C编译器将按照n个字节对齐。 #pragma pack () 作用:取消自定义字节对齐方式。 #...
  • 关于C语言中的结构体字节对齐问题,在《C与指针》一书中提到,但是似乎没有说清楚,还是我理解不完全?所以,根据书上和网上资料,总结一些关于C语言中的结构体字节对齐的知识。这里的讨论和代码,都在VS2010下,GCC...
  • 本文主要讲了什么是字节对齐,为什么要对齐,已经应该注意的一些问题,下面一起来看看
  • VS C++字节对齐方式

    2020-12-18 23:56:48
    VS C++字节对齐方式
  • 对于字节占用与对齐,excel表格中做了稍微修改,与12-27号版本比较,代码没有改动。
  • 本篇文章是对C++内存中字节对齐的问题进行了详细的分析与总结。需要的朋友参考下
  • 字节对齐小结

    2013-10-14 14:11:42
    简明扼要的介绍了什么是字节对齐,为什么要字节对齐,对字节对齐从硬件存取上来讲的
  • C语言字节对齐 https://blog.csdn.net/21aspnet/article/details/6729724 文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透。  一、概念    对齐跟数据在内存中的位置...

    C语言字节对齐

    https://blog.csdn.net/21aspnet/article/details/6729724

     

    文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透。

      一、概念
      
       对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的。
      
      二、为什么要字节对齐
      
       需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求非常严格,比如sparc系统,如果取未对齐的数据会发生错误,举个例:
      
      char ch[8];
      char *p = &ch[1];
      int i = *(int *)p;
      
      
      运行时会报segment error,而在x86上就不会出现错误,只是效率下降。
      
      三、正确处理字节对齐
      
       对于标准数据类型,它的地址只要是它的长度的整数倍就行了,而非标准数据类型按下面的原则对齐:
      
      数组 :按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。
      联合 :按其包含的长度最大的数据类型对齐。
      结构体: 结构体中每个数据类型都要对齐。
      比如有如下一个结构体:
      
      struct stu{
       char sex;
       int length;
       char name[10];
      };
      struct stu my_stu;
      
      
      由于在x86下,GCC默认按4字节对齐,它会在sex后面跟name后面分别填充三个和两个字节使length和整个结构体对齐。于是我们sizeof(my_stu)会得到长度为20,而不是15.
      
      四、__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)是位对齐.
      
      五、什么时候需要设置对齐
      
       在设计不同CPU下的通信协议时,或者编写硬件驱动程序时寄存器的结构这两个地方都需要按一字节对齐。即使看起来本来就自然对齐的也要使其对齐,以免不同的编译器生成的代码不一样.

     

    一、快速理解

    1. 什么是字节对齐?

    在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然边界(alignment)分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。

    为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”. 比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除.

    2. 字节对齐有什么作用?

    字节对齐的作用不仅是便于cpu快速访问,同时合理的利用字节对齐可以有效地节省存储空间。

    对于32位机来说,4字节对齐能够使cpu访问速度提高,比如说一个long类型的变量,如果跨越了4字节边界存储,那么cpu要读取两次,这样效率就低了。但是在32位机中使用1字节或者2字节对齐,反而会使变量访问速度降低。所以这要考虑处理器类型,另外还得考虑编译器的类型。在vc中默认是4字节对齐的,GNU gcc 也是默认4字节对齐。

    3. 更改C编译器的缺省字节对齐方式

    在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
    · 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
    · 使用伪指令#pragma pack (),取消自定义字节对齐方式。

    另外,还有如下的一种方式:
    · __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
    · __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

    4. 举例说明

    例1

    struct test
    {
    char x1;
    short x2;
    float x3;
    char x4;
    };

    由于编译器默认情况下会对这个struct作自然边界(有人说“自然对界”我觉得边界更顺口)对齐,结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间填充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然边界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4字节对界,是该结构所有成员中要求的最大边界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间为12字节。

    例2

    #pragma pack(1) //让编译器对这个结构作1字节对齐
    struct test
    {
    char x1;
    short x2;
    float x3;
    char x4;
    };
    #pragma pack() //取消1字节对齐,恢复为默认4字节对齐

    这时候sizeof(struct test)的值为8。

    例3

    #define GNUC_PACKED __attribute__((packed))
    struct PACKED test
    {
    char x1;
    short x2;
    float x3;
    char x4;
    }GNUC_PACKED;

    这时候sizeof(struct test)的值仍为8。

    二、深入理解

    什么是字节对齐,为什么要对齐?
    TragicJun 发表于 2006-9-18 9:41:00 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
          对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。
    二.字节对齐对程序的影响:

            先让我们看几个例子吧(32bit,x86环境,gcc编译器):
    设结构体如下定义:
    struct A
    {
            int a;
            char b;
            short c;
    };
    struct B
    {
            char b;
            int a;
            short c;
    };
    现在已知32位机器上各种数据类型的长度如下:
    char:1(有符号无符号同)   
    short:2(有符号无符号同)   
    int:4(有符号无符号同)   
    long:4(有符号无符号同)   
    float:4        double:8
    那么上面两个结构大小如何呢?
    结果是:
    sizeof(strcut A)值为8
    sizeof(struct B)的值却是12

    结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个,B也一样;按理说A,B大小应该都是7字节。
    之所以出现上面的结果是因为编译器要对数据成员在空间上进行对齐。上面是按照编译器的默认设置进行对齐的结果,那么我们是不是可以改变编译器的这种默认对齐设置呢,当然可以.例如:
    #pragma pack (2) /*指定按2字节对齐*/
    struct C
    {
            char b;
            int a;
            short c;
    };
    #pragma pack () /*取消指定对齐,恢复缺省对齐*/
    sizeof(struct C)值是8。
    修改对齐值为1:
    #pragma pack (1) /*指定按1字节对齐*/
    struct D
    {
            char b;
            int a;
            short c;
    };
    #pragma pack () /*取消指定对齐,恢复缺省对齐*/
    sizeof(struct D)值为7。
    后面我们再讲解#pragma pack()的作用.

    三.编译器是按照什么样的原则进行对齐的?

            先让我们看四个重要的基本概念:


    1.数据类型自身的对齐值:
          对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
    2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
    3.指定对齐值:#pragma pack (value)时的指定对齐值value。
    4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
    有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍,结合下面例子理解)。这样就不能理解上面的几个例子的值了。
    例子分析:
    分析例子B;
    struct B
    {
            char b;
            int a;
            short c;
    };
    假设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值默认为4。第一个成员变量b的自身对齐值是1,比指定或者默认指定对齐值4小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.第二个成员变量a,其自身对齐值为4,所以有效对齐值也为4,所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自身对齐值为2,所以有效对齐值也是2,可以存放在0x0008到0x0009这两个字节空间中,符合0x0008%2=0。所以从0x0000到0x0009存放的都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求,0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B共有12个字节,sizeof(struct B)=12;其实如果就这一个就来说它已将满足字节对齐了,因为它的起始地址是0,因此肯定是对齐的,之所以在后面补充2个字节,是因为编译器为了实现结构数组的存取效率,试想如果我们定义了一个结构B的数组,那么第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨着的,如果我们不把结构的大小补充为4的整数倍,那么下一个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了,因此我们要把结构补充成有效对齐大小的整数倍.其实诸如:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,这些已有类型的自身对齐值也是基于数组考虑的,只是因为这些类型的长度已知了,所以他们的自身对齐值也就已知了.
    同理,分析上面例子C:
    #pragma pack (2) /*指定按2字节对齐*/
    struct C
    {
            char b;
            int a;
            short c;
    };
    #pragma pack () /*取消指定对齐,恢复缺省对齐*/
    第一个变量b的自身对齐值为1,指定对齐值为2,所以,其有效对齐值为1,假设C从0x0000开始,那么b存放在0x0000,符合0x0000%1=0;第二个变量,自身对齐值为4,指定对齐值为2,所以有效对齐值为2,所以顺序存放在0x0002、0x0003、0x0004、0x0005四个连续字节中,符合0x0002%2=0。第三个变量c的自身对齐值为2,所以有效对齐值为2,顺序存放
    在0x0006、0x0007中,符合0x0006%2=0。所以从0x0000到0x00007共八字节存放的是C的变量。又C的自身对齐值为4,所以C的有效对齐值为2。又8%2=0,C只占用0x0000到0x0007的八个字节。所以sizeof(struct C)=8.

    四.如何修改编译器的默认对齐值?

    1.在VC IDE中,可以这样修改:[Project]|[Settings],c/c++选项卡Category的Code Generation选项的Struct Member Alignment中修改,默认是8字节。
    2.在编码时,可以这样动态修改:#pragma pack .注意:是pragma而不是progma.

    五.针对字节对齐,我们在编程中如何考虑?
            如果在编程的时候要考虑节约空间的话,那么我们只需要假定结构的首地址是0,然后各个变量按照上面的原则进行排列即可,基本的原则就是把结构中的变量按照类型大小从小到大声明,尽量减少中间的填补空间.还有一种就是为了以空间换取时间的效率,我们显示的进行填补空间进行对齐,比如:有一种使用空间换时间做法是显式的插入reserved成员:
                 struct A{
                   char a;
                   char reserved[3];//使用空间换时间
                   int b;
    }

    reserved成员对我们的程序没有什么意义,它只是起到填补空间以达到字节对齐的目的,当然即使不加这个成员通常编译器也会给我们自动填补对齐,我们自己加上它只是起到显式的提醒作用.

    六.字节对齐可能带来的隐患:

            代码中关于对齐的隐患,很多是隐式的。比如在强制类型转换的时候。例如:
    unsigned int i = 0x12345678;
    unsigned char *p=NULL;
    unsigned short *p1=NULL;

    p=&i;
    *p=0x00;
    p1=(unsigned short *)(p+1);
    *p1=0x0000;
    最后两句代码,从奇数边界去访问unsignedshort型变量,显然不符合对齐的规定。
    在x86上,类似的操作只会影响效率,但是在MIPS或者sparc上,可能就是一个error,因为它们要求必须字节对齐.

    七.如何查找与字节对齐方面的问题:

    如果出现对齐或者赋值问题首先查看
    1. 编译器的big little端设置
    2. 看这种体系本身是否支持非对齐访问
    3. 如果支持看设置了对齐与否,如果没有则看访问时需要加某些特殊的修饰来标志其特殊访问操作

    举例:

     
    1. #include <stdio.h>

    2. main()

    3. {

    4. struct A {

    5. int a;

    6. char b;

    7. short c;

    8. };

    9.  
    10. struct B {

    11. char b;

    12. int a;

    13. short c;

    14. };

    15.  
    16. #pragma pack (2) /*指定按2字节对齐*/

    17. struct C {

    18. char b;

    19. int a;

    20. short c;

    21. };

    22. #pragma pack () /*取消指定对齐,恢复缺省对齐*/

    23.  
    24.  
    25.  
    26. #pragma pack (1) /*指定按1字节对齐*/

    27. struct D {

    28. char b;

    29. int a;

    30. short c;

    31. };

    32. #pragma pack ()/*取消指定对齐,恢复缺省对齐*/

    33.  
    34. int s1=sizeof(struct A);

    35. int s2=sizeof(struct B);

    36. int s3=sizeof(struct C);

    37. int s4=sizeof(struct D);

    38. printf("%d\n",s1);

    39. printf("%d\n",s2);

    40. printf("%d\n",s3);

    41. printf("%d\n",s4);

    42. }


    输出:

    8

    12

    8

    7

     

    修改代码:

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

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

    输出:

    4

    4

    输出都是4,说明之前的int影响对齐!

     

    看图就明白了

    展开全文
  • c++内存中字节对齐问题详解
  • 字节对齐、8字节对齐

    千次阅读 2020-04-20 14:10:02
    在内存管理中经常使用字节对齐来管理分配的内存。 1、原理 2字节对齐:要求地址位为2, 4, 6, 8…,地址的二进制最后一位为0(2的1次方)。 4字节对齐:要求地址位为4,8,12,16…,地址的二进制最后两位为0(2的2...

    参考博文:参考1参考2参考3


    在内存管理中经常使用字节对齐来管理分配的内存。
    1、原理

    • 2字节对齐:要求地址位为2, 4, 6, 8…,地址的二进制最后一位为0(2的1次方)。
    • 4字节对齐:要求地址位为4,8,12,16…,地址的二进制最后两位为0(2的2次方)。
    • 8字节对齐:要求地址位为8,16,24,32…,地址的最后三位为0(2的3次方)。
    • 16字节对齐:要求地址位为16,32,48,64…,地址的最后四位为0(2的4次方)。

    2、算法
    2.1

    unsigned int calc_align(unsigned int n,unsigned align)
    {
        if ( n / align * align == n)
    	return n;
        return  (n / align + 1) * align;
    }

    2.2 更好的算法

    unsigned int calc_align(unsigned int n,unsigned align)
    {
        return ((n + align - 1) & (~(align - 1)));
    } 

    3、算法说明

    (1) (align - 1):表示对齐所需的对齐位,如:

    • 2字节对齐位为1;
    • 4字节对齐位为11;
    • 8字节对齐位111;
    • 16字节对齐位为1111;

    (2) (n + align - 1):表示n补齐对齐所需数据。
    (3) &(~(align - 1)):表示去除由于补齐造成的多余数据。
    (4) (n + align - 1) & (~(align - 1)):表示对齐后的数据。

    展开全文
  • 什么是字节对齐,为什么需要字节对齐

    万次阅读 多人点赞 2019-09-07 14:58:43
     另外字节对齐的作用不仅是便于cpu快速访问,同时合理的利用字节对齐可以==有效地节省存储空间==。  也即CPU一次访问时,要么读0x01~0x04,要么读0x05~0x08…硬件不支持一次访问就读到0x02~0x05  例:...

    概念

      在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然边界(alignment)分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。

      为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”,比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除,也即对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。

      比如在32位cpu下,假设一个整型变量的地址为0x00000004(为4的倍数),那它就是自然对齐的,而如果其地址为0x00000002(非4的倍数)则是非对齐的。

      现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

    为什么要字节对齐

      需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。

      而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求非常严格,比如sparc系统,如果取未对齐的数据会发生错误,而在x86上就不会出现错误,只是效率下降。

      各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。

      比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐,但其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。

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

      另外字节对齐的作用不仅是便于cpu快速访问,同时合理的利用字节对齐可以==有效地节省存储空间==。

      也即CPU一次访问时,要么读0x01~0x04,要么读0x05~0x08…硬件不支持一次访问就读到0x02~0x05

      例:如果0x02~0x05存了一个int,读取这个int就需要先读0x01~0x04,留下0x02~0x04的内容,再读0x05~0x08,留下0x05的内容,两部分拼接起来才能得到那个int的值,这样读一个int就要两次内存访问,效率就低了。 

    111

    针对字节对齐,我们在编程中如何考虑?

      如果在编程的时候要考虑节约空间的话,那么我们只需要假定结构的首地址是0,然后各个变量按照上面的原则进行排列即可,基本的原则就是把结构中的变量按照类型大小从小到大声明,尽量减少中间的填补空间,还有一种就是为了以空间换取时间的效率,我们显示的进行填补空间进行对齐,比如:有一种使用空间换时间做法是显式的插入reserved成员:

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

    reserved成员对我们的程序没有什么意义,它只是起到填补空间以达到字节对齐的目的,当然即使不加这个成员通常编译器也会给我们自动填补对齐,我们自己加上它只是起到显式的提醒作用。

    字节对齐可能带来的隐患

      代码中关于对齐的隐患,很多是隐式的,比如在强制类型转换的时候,例如:

    unsigned int i = 0x12345678;
    unsigned char *p = NULL;
    unsigned short *p1 = NULL;
    
    p = &i;                            //这里可假设p指向了一个4的整数倍地址,例如0x04
    *p = 0x00;                         
    p1 = (unsigned short *)(p + 1);    //这里p1指向了p后移一位,也即为0x05
    *p1 = 0x0000;

    这样最后两句代码,从奇数边界去访问unsigned short型变量,显然不符合对齐的规定,在x86上,类似的操作只会影响效率,但是在MIPS或者sparc上,可能就是一个error,因为它们要求必须字节对齐。

    展开全文
  • 深入理解字节对齐

    2020-03-15 20:24:38
    C语言--字节对齐基础知识了解一、操作系统位数、CPU位数、指令集1.操作系统--32-bit(x86)和64-bit(x64)(1)位数(2)64-bit2.处理器CPU位数3.CPU指令集4.寄存器5.关系6.计算机字长(机器字长)7.总结理解字节对齐二...

    基础知识了解

    一、操作系统位数、CPU位数、指令集

    1.操作系统–32-bit(x86)和64-bit(x64)

    (1)位数

      每个时钟周期内,处理器处理二进制代码数,即“0”和“1”的个数。

    (2)64-bit

      优点:①可以进行更大范围的整数运算;②可以支持更大的内存。

    2.处理器CPU位数

      CPU位数=CPU中寄存器的位数=CPU能够一次并行处理的数据宽度(位数)=数据总线宽度;
      //现在的计算机处理器一般都是64位,这是硬件的事。

    3.CPU指令集

      CPU为了实现其功能设计了指令集,即是CPU的全部指令,这是机器语言。计算机的所有功能都是基于CPU的指令集。指令集和CPU的位数是有联系的。

      指令集的作用, 就是告诉程序员/编译器, 汇编一定要有格式. 支持什么指令, 指令带什么限制条件, 用什么操作数, 用什么地址, 都是指令集规范的内容, 要是写错了, 就无法翻译成机器码.

      指令集规范汇编, 汇编可以翻译成机器码, 机器码告诉CPU每个周期去做什么. 因此, CPU指令集是描述CPU能实现什么功能的一个集合, 就是描述"CPU能使用哪些机器码"的集合"。X86是指令集的代号。
      那么指令集在CPU里就代表: 只有CPU指令集范围内的指令可以被成功的译码, 并送往CPU流水线后端去执行.

    4.寄存器

      寄存器是CPU内部用来创建和储存CPU运算结果和其它运算结果的地方。

    5.关系

      操作系统位数 = 其所依赖的指令集位数 <= CPU位数。

    6.计算机字长(机器字长)

      计算机字长(机器字长)取决于数据总线的宽度,通常就是CPU一次能处理的数据的位数(CPU位数)。

    7.总结

      在标准c++中,int的定义长度要依靠你的机器的字长,也就是说,如果你的机器是32位的,int的长度为32位,如果你的机器是64位的,那么int的标准长度就是64位,比如16位机上,sizeof(int) = 2,而32位机上sizeof(int) = 4;32位机上sizeof(long) = 4,而64位机上sizeof(long) = 8。

      但是在32位机器和64机器中int类型都占用4个字节,因为一般编译器可以根据自身硬件来选择合适的大小,但是需要满足约束:short和int型至少为16位,long型至少为32位,并且short型长度不能超过int型,而int型不能超过long型

      这即是说各个类型的变量长度是由编译器来决定的,而当前主流的编译器中一般是32位机器和64位机器中int型都是4个字节(例如,GCC)。

    理解字节对齐

    二、字节对齐

    1.什么是字节对齐?

      现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。

      变量存的起始地址必须具备某些特性----“对齐”,比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除。


      对齐跟数据在内存中的位置有关。为了使得CPU能快速对变量进行访问,变量存的起始地址必须具备某些特性,即“对齐”,比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除。====>>>>cpu类型,编译器类型。

    2.为什么要字节对齐

    ①首先,不同硬件平台对存储空间的处理上存在不同;

      某些平台对特定类型的数据只能从特定地址开始存取,而不允许其在内存中任意存放。例如,Motorola 68000 处理器不允许16位的字存放在奇地址,否则会触发异常,因此在这种架构下编程必须保证字节对齐。

    ②根本原因在于CPU访问数据的效率问题;

      以32位机为例,它每次取32个位,也就是4个字节。以int型数据为例,如果它在内存中存放的位置按4字节对齐,也就是说1个int的数据全部落在计算机一次取数的区间内,那么只需要取一次就可以了。如图2-1。如果不对齐,很不巧,这个int数据刚好跨越了取数的边界,这样就需要取两次才能把这个int的数据全部取到,如图2-2,这样效率也就降低了。
    在这里插入图片描述

    ③其次节约空间。

      应该辩证地看:合理对齐,则节约空间;否则浪费空间。如下例:
    在这里插入图片描述
      结构体TEST1中包含一个4字节的int数据,一个1字节char数据和一个2字节short数据;TEST2也一样。按理说TEST1和TEST2的大小应该都是7字节。之所以出现上述结果,就是因为编译器要对数据成员在空间上进行对齐。

    3.如何对齐

    3.1 标准类型(基本数据类型):

      基本类型包括char、int、float、double、short、long等基本数据类型。
      对齐要求:起始地址为其长度的整数倍即可。如,int类型的变量起始地址要求为4的整数倍。
    思考:int究竟占多少个字节?
      **操作系统:**每个时钟周期内,处理器处理二进制代码数,即“0”和“1”的个数。如64-bit,32-bit
      **CPU位数:**CPU中寄存器的位数=CPU能够一次并行处理的数据宽度(位数)=数据总线宽度;64-bit,32-bit。
      **关系:**操作系统位数 = 其所依赖的指令集位数 <= CPU位数。

    int的定义长度要依靠机器的字长,由编译器结合自身硬件选择。

    约束条件: short和int型至少为16位,long型至少为32位,并且short型长度不能超过int型,而int型不能超过long型。这即是说各个类型的变量长度是由编译器来决定的,而当前主流的编译器中一般是32位机器和64位机器中int型都是4个字节。

      理论上,int代表机器自然长度,即CPU位数,在32位CPU,应该占4字节,64位CPU,应该占8字节。
      实际上,由编译器和CPU共同决定,主流的编译器编译程序将int解释为4字节。
    在这里插入图片描述

    3.2 数组:

      按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。

    3.3 结构体

      成员可以为:基本类型,复合类型(基本类型、数组、结构、联合、函数指针)
      结构体中每个数据类型都要对齐,对齐值位其成员中自身对齐值最大的那个值。
    在这里插入图片描述在这里插入图片描述

    3.4 联合体

      联合体的内存除了取最大成员内存外,还要保证是所有成员类型size的最小公倍数。
    在这里插入图片描述
      
       当然只取最大的int数组的大小12没错,但是double是8字节的,而此时联合体已经按int的4字节对齐了,所以还要额外多加4字节的内存来保证8的倍数。所以最后结果是16。

      所以联合体的内存除了取最大成员内存外,还要保证是所有成员类型size的最小公倍数

    3.5 指定对齐方式

       #pragma pack(n)   //设置n字节对齐
      #pragma pack()   //取消自定义字节对齐方式

      以n和结构体中最长的成员的长度中较小者为其值。

      __attribute((aligned (n))) //设置n字节对齐
      attribute ((packed))   //设置1字节对齐
      (gcc特性)

      让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
    在这里插入图片描述
      微软的  __alignof( type )
      如:
        typedef __declspec(align(32)) struct { int a; } S;
        _alignof(S) 等于 32

    总结:
      ①基本类型:自身对齐
      ②数组:
      ③联合:成员最大对齐值,公倍数;
      ④结构体:其成员中自身对齐值最大的那个值。
      ⑤指定对齐方式:
        #pragma pack (n)和pragma pack ();
        attribute((aligned(n)))和__attribute__((packed))。
      ⑥数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小者,即有效对齐值=min{自身对齐值,当前指定的pack值};注意_attribute__。

    4.字节序和网络序

    4.1 字节序

    (1) what–
      概念:字节的高低位存放顺序。
      单字节与多字节:
        单字节:按bit存储,通常处理方式相同;
        多字节:多个字节存储有顺序之分。
    在这里插入图片描述
    (2) how–
      大字节序(Big-Endian,大端序):最高有效字节在最前面的方式。
      小字节序(Little-Endian,小端序):最低有效字节在最前面的方式。
    在这里插入图片描述
    (3) why–
      编写网络程序时,主机之间通过网络相互通信,不同主机之间可能采用不同的方法,而且网络字节序和主机字节序也可能不同。
    在这里插入图片描述在这里插入图片描述

    4.2 网络序

      网络传输一般采用大字节序,也称为网络字节序或网络序。IP协议中定义大字节序为网络字节序。

      对于可移植的代码来说,将接收的网络数据转换成主机的字节序是必须的,一般会有成对的函数用于把网络数据转换成相应的主机字节序或反之。

    转换函数:
      Htonl、htons用于主机序转换到网络序;
      ntohl、ntohs用于网络序转换到本机序。
      
    注意:
      对于单字符或小于单字符的几个bit数据,是不必转换的,因为在机器存储和网络发送的一个字符内的bit位存储顺序是一致的。

    5.字节对齐的隐患

      空间换时间。

    6.字节对齐应用

      本地
      网络传输

    代码验证:
      环境:
      操作系统:x86_64-redhat-linux;编译器:gcc
      操作系统:win7-64位;编译器:vc

    展开全文
  • 亲自编写 测试通过 可用于工程项目通信
  • 字节对齐

    千次阅读 2020-03-01 11:12:21
    一、什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要...
  • C++字节对齐

    2019-05-15 14:45:58
    C和C++字节对齐 文章目录C和C++字节对齐1. 什么是字节对齐2. 对齐的原因和作用3. 对齐准则4. 结果分析5. 字节对齐设置 1. 什么是字节对齐   现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问...
  • 结构体字节对齐

    千次阅读 2019-01-30 18:42:23
    结构体字节对齐
  • 下面小编就为大家带来一篇C++对象内存分布详解(包括字节对齐和虚函数表)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 字节对齐 struct示例 内存布局 优化结构体内存空间 Java字节对齐 上一篇日志最后说到,非静态类型变量的经过起始偏移量和5中类型偏移量计算后,在统计总的内存空间大小前,需要进行内存对齐补白操作,这样做的...
  • 详解4字节对齐

    2020-08-18 15:14:28
    所谓的字节对齐,就是各种类型的数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这个就是对齐。我们经常听说的对齐在N上,它的含义就是数据的存放起始地址%N==0。具体对齐规则会在下面的篇幅中介绍...
  • 关于编译器的字节对齐 (转)

    千次阅读 2019-01-02 08:42:36
    但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 一.对齐的作用和原因: 各个硬件平台对存储空间...
  • 字节对齐的规则总结

    万次阅读 多人点赞 2017-09-15 11:11:44
    一、什么是字节对齐,为什么要对齐?现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要...
  • C语言字节对齐

    2013-06-27 08:47:44
    本文档从硬件角度讲述产生字节对齐的根本原因,并对字节对齐的多种情况作了较为详细的说明,并对字节对齐产生的一些影响做了说明
  • C语言字节对齐详解

    万次阅读 多人点赞 2018-03-22 20:41:27
    C语言字节对齐12345不同系统下的C语言类型长度 Data Type ILP32 ILP64 LP64 LLP64 char 8 8 8 8 short 16 16 16 16 int 32 64 32 32 long 32 64 64 32 long long 64 64 64
  • c语言字节对齐

    2017-04-26 13:14:19
    c语言字节对齐

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 135,379
精华内容 54,151
关键字:

字节对齐