zoukankan      html  css  js  c++  java
  • #Pragma Pack(n)与内存分配

     #pragma pack(n)

    解释一:

    每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

     

      规则:

     

      1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

     

      2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

    解释二:

    n 字节的对齐方式 VC 对结构的存储的特殊处理确实提高 CPU 存储变量的速度,但是有时候也带来 了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。 VC 中提供了#pragma pack(n)来设定变量以 n 字节对齐方式。n 字节对齐就是说 变量存放的起始地址的偏移量有两种情况:

    第一、如果 n 大于等于该变量所占用的字 节数,那么偏移量必须满足默认的对齐方式。

    第二、如果 n 小于该变量的类型所占用 的字节数,那么偏移量为 n 的倍数,不用满足默认的对齐方式。结构的总大小也有个 约束条件,分下面两种情况:如果 n 大于所有成员变量类型所占用的字节数,那么结 构的总大小必须为占用空间最大的变量占用的空间数的倍数; 否则必须为 n 的倍数。

    下面举例说明其用法。 #pragma pack(push) //保存对齐状态

     #pragma pack(4)//设定为 4 字节对齐

    struct test { char m1; double m4; int m3; }; #pragma pack(pop)//恢复对齐状态 以上结构体的大小为 16:

    下面分析其存储情况,首先为 m1 分配空间,其偏移量 为 0,满足我们自己设定的对齐方式(4 字节对齐),m1 大小为 1 个字节。接着开始 为 m4 分配空间,这时其偏移量为 1,需要补足 3 个字节,这样使偏移量满足为 n=4 的倍数(因为 sizeof(double)大于 4),m4 占用 8 个字节。接着为 m3 分配空间,这时 其偏移量为 12,满足为 4 的倍数,m3 占用 4 个字节。这时已经为所有成员变量分配 了空间,共分配了 16 个字节,满足为 n 的倍数。如果把上面的#pragma pack(4)改为 #pragma pack(8),那么我们可以得到结构的大小为 24。

    大家看了这些文字描述头也一定会发麻吧,我坚持读完后,然后自己编写了一个程序:

    #pragma pack(4)

    struct node{

      int e;
      char f;
      short int a;
      char b;

    };

    struct node n;

    printf("%d ",sizeof(n));

    我自己算的结果是16,结果实际结果是:

    然后结构体内部数据成员变动一下位置:

    #pragma pack(4)

    struct node{

      char f;
      int e;
      short int a;
      char b;};

    struct node n;

    printf("%d ",sizeof(n));

    将对齐位数强制定位2

    #pragma pack(2)

    struct node{

      char f;
      int e;
      short int a;
      char b;};

    struct node n;

    printf("%d ",sizeof(n));

    将对齐位数强制定位1

    #pragma pack(1)

    struct node{

      char f;
      int e;
      short int a;
      char b;};

    struct node n;

    printf("%d ",sizeof(n));

    看着输出结果和文字描述有点晕,下面简单说一下俺的判定规则吧:

    其实之所以有内存字节对齐机制,就是为了最大限度的减少内存读取次数。我们知道CPU读取速度比内存读取速度快至少一个数量级,所以为了节省运算花费时间,只能以牺牲空间来换取时间了。

    下面举例说明如何最大限度的减少读取次数。

    #pragma pack(1)

    struct node{

      char f;
      int e;
      short int a;
      char b;};

    struct node n;

    printf("%d ",sizeof(n));

    这里强制按照1字节进行对齐,可以理解成所有的内容都是按照1字节进行读取(暂且这样理解,因为这样可以很好的理解内存对其机制),其他所有的数据成员都是1字节的整数倍,所以也就不用进行内存对其,各个成员在内存中就按照实际顺序进行排列,结构体实际长度为8

    #pragma pack(2)

    struct node{

      char f;
      int e;
      short int a;
      char b;};

    struct node n;

    printf("%d ",sizeof(n));

    这里强制按照2字节进行对齐。如果内存分布仍然是连续的话,那么int e就得三次才能读到CPU中,所以为了“讲究”int e的读取,所以在char f之后预留1BYTE,最后的char b也是如此,所以长度为10

    #pragma pack(4)

    struct node{

      char f;
      int e;
      short int a;
      char b;};

    struct node n;

    printf("%d ",sizeof(n));

    这里强制按照4字节进行对齐。所以char f后要预留3BYTE,而short int a 和 char b可以一次读取到CPU(按照4字节读取),所以长度为12

    如果#pramga pack(n)中的n大于结构体成员中任何一个成员所占用的字节数,则该n值无效。编译器会选取结构体中最大数据成员的字节数为基准进行对其

  • 相关阅读:
    创建Variant数组
    ASP与存储过程(Stored Procedures)
    FileSystemObject对象成员概要
    Kotlin 朱涛9 委托 代理 懒加载 Delegate
    Kotlin 朱涛 思维4 空安全思维 平台类型 非空断言
    Kotlin 朱涛7 高阶函数 函数类型 Lambda SAM
    Kotlin 朱涛16 协程 生命周期 Job 结构化并发
    Proxy 代理模式 动态代理 cglib MD
    RxJava 设计理念 观察者模式 Observable lambdas MD
    动态图片 Movie androidgifdrawable GifView
  • 原文地址:https://www.cnblogs.com/decode1234/p/6595008.html
Copyright © 2011-2022 走看看