zoukankan      html  css  js  c++  java
  • 结构体内存对齐

    一.为什么要对齐?
     
    《Windows核心编程》里这样说:当CPU访问正确对齐的数据时,它的运行效率最高,当数据大小的数据模数的内存地址是0时,数据是对齐的。例如:WORD值应该是总是从被2除尽的地址开始,而DWORD值应该总是从被4除尽的地址开始,数据对齐不是内存结构的一部分,而是CPU结构的一部分。当CPU试图读取的数值没有正确的对齐时,CPU可以执行两种操作之一:产生一个异常条件;执行多次对齐的内存访问,以便读取完整的未对齐数据,若多次执行内存访问,应用程序的运行速度就会慢。在最好的情况下,是两倍的时间,有时更长。
     
    二.成员变量对齐的原理
     
    内存对齐遵循两个原则:
      1. 成员的内存对齐。成员在内存中的起始位置必须是{其所需内存大小与编译器预设的一个字节数}取较小值的整数倍。
      2. 结构体整体的内存对齐。结构体整体所占内存大小需是{所有成员中占内存最大的与编译器预设的一个字节数}取较小的整数倍。
    对于
    struct s1
    {
     
    char a;
    long int d;
    double c;
    };
     
    成员a在内存0的位置;成员d大小为4,编译器预设的字节数为8,那么它按4字节对齐,所以存在偏移4-7的位置;c的大小为8,按8字节对齐,存在8-15的位置。整个结构体占16字节内存。由于内存成员最大为8,取它与编译器预设字节8较小值,因此结构体所占内存需调整为8的整数倍,而16刚好是8的整数倍,无需调整。因此,该结构体所占内存为16。
     
    而对于
    struct s2
     
    {
     
    char a;
     
    long int d;
     
    double c;
     
    char e;
     
    };
     
    前三个成员和s1一样。成员e是1字节的,按1字节对齐(任何偏移位置都是1的整数倍),放在位置16。因此,整个结构体占17字节。同上,结构体按照8字节对齐,所以结构体占24字节内存。
     
     
    当然你可以使用#pragma指令指定编译器按4字节对齐。即
     
    #pragma pack(4)       // 这里也可以是#pragma pack(push,4)
     
    struct s1
     
    {
     
    char a;
     
    long int d;
     
    double c;
     
    };
     
    struct s2
     
    {
     
    char a;
     
    long int d;
     
    double c;
     
    char e;
     
    };
     
     这时s1的大小还是16,所有成员存放的位置也和前边一样。不同的是,虽然成员c仍放在8-15的位置,但它是按4字节对齐而非原先的8字节,只是比较巧,内存偏移8既是8的倍数也是4的倍数。而且,最终结构体的对齐也是按4字节对齐而不是之前的8,只是16既是8的倍数也是4的倍数,因此无需调整。
    s2的成员存放也同之前的情况,最终结构体占17字节内存。17按4字节对齐是20,所以此时s2占20字节的内存!
     
    你也看到并不是指定编译器按4字节对齐就按4字节对齐的。比如下面的结构体:
     
    #pragma pack(4)
     
    struct TestStruct2
     
    {
     
        char m1[11];
     
        short m2;
     
    };
     
    你知道它的大小吗?是14。因为m1按1字节对齐,存诸在0——10位置,m2按2字节对齐,存诸在12——13位置。结构体占用14个字节,因为结构体内最大的成员的数据类型是short,大小为2,比指定的对齐字节4小,所以14对2园整,得14。
     
     
    总的说来就是结构成员的对齐是用成员大小和#pragma pack(push,n)中的n中较小的数对齐,例如如果成员大小为2,而你指定的对齐方式是4,则该成员按2对齐;结构本身的对其是用结构中最大成员的大小和#pragma pack(push,n)中的n较小的数对齐,即最后的园整,例如如果结构中最大成员大小8,而你指定对齐是16,则结构本身按8对齐。
  • 相关阅读:
    xmlHttpRequest参数
    蒙哥马利:“沙漠之狐”猎手
    c# as is 类型转换
    值类型和引用类型
    BuuctfmiscN种方法解决
    Buuctfmisc二维码
    Buuctfweb[HCTF 2018]WarmUp
    Buuctfmisc大白
    map用索引作下标之后,再插值时报错.
    c++ stl 的string 的size() legth()区别
  • 原文地址:https://www.cnblogs.com/lulu10922/p/5803722.html
Copyright © 2011-2022 走看看