精华内容
下载资源
问答
  • 为什么要字节对齐

    2018-03-20 11:41:41
    2.硬件原因:经过内存对齐之后,CPU的内存访问速度大大提升(因为任意数据或者结构体都是从偏移量0的地方开始存储的,经过字节对齐后,他们的大小都是2的整数倍,正好符合cpu按块读取数据的规则,这样的话,cpu...

    1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常

    2.硬件原因:经过内存对齐之后,CPU的内存访问速度大大提升(因为任意数据或者结构体都是从偏移量为0的地方开始存储的,经过字节对齐后,他们的大小都是2的整数倍,正好符合cpu按块读取数据的规则,这样的话,cpu每次都是读取一个或者若干个块,不需要再删除里面不需要的数据了,从而提高了读的速度)。具体原因接下来解释

    图一:这里写图片描述

    我们普通程序员心中的内存印象,由一个个字节组成,但是CPU却不是这么看待的

    图二:
    这里写图片描述

    cpu把内存当成是一块一块的,块的大小可以是2,4,8,16 个字节,因此CPU在读取内存的时候是一块一块进行读取的,块的大小称为(memory granularity)内存读取粒度。

    我们再来看看为什么内存不对齐会影响读取速度?

    假设CPU要读取一个4字节大小的数据到寄存器中(假设内存读取粒度是4),分两种情况讨论:
    
           1.数据从0字节开始
    

       2.数据从1字节开始

    解析:当数据从0字节开始的时候,直接将0-3四个字节完全读取到寄存器,结算完成了。

        当数据从1字节开始的时候,问题很复杂,首先先将前4个字节读到寄存器,并再次读取4-7字节的数据进寄存器,接着把0字节,4,6,7字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器,对一个内存未对齐的寄存器进行了这么多额外操作,大大降低了CPU的性能。
    
     但是这还属于乐观情况,上文提到内存对齐的作用之一是平台的移植原因,因为只有部分CPU肯干,其他部分CPU遇到未对齐边界就直接罢工了。
    
    展开全文
  • 什么是字节对齐为什么要对齐 现代计算机中内存空间都是按照BYTE划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种...
  • 一、什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要...

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

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

    ————————————————
    版权声明:本文为CSDN博主「susan19890313」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/susan19890313/article/details/7489848

    展开全文
  • 什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要...

    http://blog.csdn.net/xhfwr/archive/2006/07/23/963793.aspx
    一.什么是字节对齐,为什么要对齐?
    现代计算机中内存空间都是按照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. 如果支持看设置了对齐与否,如果没有则看访问时需要加某些特殊的修饰来标志其特殊访问操作。

    展开全文
  • 什么是字节对齐? ...为什么要字节对齐? 可优化【读写效率】【空间存储】【跨平台通信】 读写效率 考虑场景如下:若计算机每次读取8字节块,此时读取一个double,若未字节对其,可能该double位与

    什么是字节对齐?

    计算机并非逐字节读取内存,而是按2,4,8的倍数的字节块读写内存,故地址必须为上述倍数,故各种数据类型需要按照一定规则在空间上排列

    对齐准则

    • 结构体变量首地址可被对齐字节数大小所整除
    • 结构体每个成员相对该结构体首地址的偏移都是成员大小的整数倍(如需要,填充字节)
    • 结构体总大小为结构体对齐字节数大小的整数倍

    为什么要字节对齐?

    可优化【读写效率】【空间存储】【跨平台通信】

    读写效率

    考虑场景如下:若计算机每次读取8字节块,此时读取一个double,若未字节对其,可能该double位与两个不同的字节块,需要做两次读取才能读出double的值,显然效率低下!

    空间存储

    字节对齐的细节由编译器实现,为何我们还需要考虑字节对齐?

    考虑如下代码

    #include<stdio.h>
    #include<stdint.h>
    #ifdef DEBUG
        struct test
        {
            int a;
            char b;   
            int c;
            short d;
            test(int v1, char v2, int v3, short v4) :
                a(v1),b(v2),c(v3),d(v4){}
        };	/* 16字节 */
    #else
        struct test
        {
            int a;
            char b;   
            short d;
            int c;
            test(int v1, char v2, int v3, short v4) :
                a(v1),b(v2),c(v3),d(v4){}
        };/* 12字节 */
    #endif
    int main(int argc, char* argv)
    {
        /*在32位和64位的机器上,size_t的大小不同*/
        struct test a(1,'a',2,3);
        printf("the size of struct test is %zu\n", sizeof(a));
        return 0;
    }
    

    实验结果如下:

    • 16字节内存分布:

    image.png

    • 12字节内存分布:

    image.png

    结论

    设计结构体时,合理调整成员的位置,可大大较少存储空间(比如说将内存占用较小的变量顺序放置)

    /* 32位机器上执行运行 */
    struct test
    {
        int a;
        char b;
        int c;
        short d;
    }; /* 大小为16字节 */
    /* 未对齐 : 0-3 , 4 , 5-8 , 9-10*/
    /* 对齐: 0-3 , 4-7 , 8-11 , 12-15*/  
    struct test{
    	int a;
        char b;
        short d;
        int c;
    }/* 对齐:0-3 , 4-5 , 6-7 , 8-11 */
    /* b和d 存储在了同一字节块 */
    

    跨平台通信

    由于不同平台对齐方式可能不同,故可采用两种处理方式。

    • 1字节对齐
    • 主动对结构【字节填充】

    1字节对齐#pragma pack(n)

    #pragma pack(1) /*1字节对齐*/
    struct test
    {
        int a;
        char b;
        int c;
        short d;
    };
    #pragma pack()/*还原默认对齐*/
    

    其内存分布如下(占11字节):
    image.png

    主动填充

    struct test
    {
        int a;
        char b;
        char reserve[3];
        int c;
        short d;
        char reserve1[2];
    };
    

    不节省空间且扩展性差,不推荐

    总结

    在编程过程中,不需要关注字节对齐的细节,但不可忽略字节对齐,故总结了如下经验:

    1. 结构体合理安排成员位置
    2. 跨平台数据可考虑1字节填充
    3. 本地数据采用默认对齐,以提高访问效率
    展开全文
  • 为什么要字节对齐?

    2020-03-17 21:41:16
    结构体(struct)或联合(union) 的数据成员,第一个数据成员放在offset0的地方,以后每个数据成员存储的起始位置从该成员的大小或该成员的子成员大小(只要该成员有子成员)的整数倍开始 . 结构体作为成员:如果一个...
  • 为什么要字节对齐

    2018-08-16 18:05:31
    文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透。  一、概念    对齐跟数据在内存中的位置有关。...比如在32位cpu下,假设一个整型变量的地址0x00000004,那它就...
  • 为什么需要字节对齐?   为什么需要字节对齐? 计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此)...
  • 为什么需要字节对齐?计算机组成原理教导我们这样有助于加快计算机的取数速度,否则 就得多花指令周期了。 为此,编译器默认会对结构体进行处理(实际上其它地方的数据变 量也是如此),让宽度为2的基本...
  • 本文主要讲了什么是字节对齐为什么要对齐,已经应该注意的一些问题,下面一起来看看
  • 一、概念   对齐跟数据在内存中的位置有关。... 二、为什么要字节对齐    需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取
  • 文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透。 一、概念 对齐跟数据在内存... 二、为什么要字节对齐 需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变...
  • 结构体填充与数据对齐 结构变量的大小等于它包含所有变量的总大小。 结构体填充:是编译器用来对齐内存偏移数据。...为什么要字节对齐? 现代计算机中内存的存储理论上都是按照 byte 大小来存储的,但实际上是
  • 一、概念  对齐跟数据在内存中的位置有关。... 二、为什么要字节对齐    需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如...
  • 什么是字节对齐,为什么要对齐

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

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,236
精华内容 494
关键字:

为什么要字节对齐