zoukankan      html  css  js  c++  java
  • C++结构体字节对齐

    转自:http://www.cnblogs.com/JensenCat/p/4770171.html

    这里是头文件结构的定义:

    一个非字节对齐结构体_tagTest2

    一个字节对齐_tagTest3

    (使用#pragma pack(push,1)来使字节以1个来对齐 , 使用#pragma pack(pop)来还原默认)

     1 #pragma once
     2 
     3  
     4  struct _tagTest1
     5  {
     6  };
     7  
     8  //非字节对齐的结果
     9  struct _tagTest2
    10  {
    11      int n1;
    12      char ch1;
    13      float f1;
    14      char szName[21];
    15      _tagTest1* pTag;
    16  };
    17  
    18  #pragma pack(push,1)
    19  //_tagTest3和2是一样的结构,字节对齐后的结果
    20  struct _tagTest3
    21  {
    22      int n1;
    23      char ch1;
    24      float f1;
    25      char szName[21];
    26      _tagTest1* pTag;
    27  };
    28  
    29 #pragma pack(pop) 

    这里是实验代码:注释处写了分析,结果也入分析所料

     1 #include "msgdef.h"
     2  #include <Windows.h>
     3  #include <iostream>
     4   using namespace std;
     5 
     6   void main()
     7  {
     8      /*
     9     非字节对齐下,当前最大的空间是4个字节,所有结构都会向4个字节对齐...
    10      int n1;                4
    11      char ch1;            4        注解:1不是4的倍数..将扩张到4 
    12      float f1;            4
    13      char szName[21];    24        注解:21不是4的倍数..将扩张到24
    14      _tagTest1* pTag;    4
    15      总和为:40
    16      */
    17      _tagTest2 k2;
    18      cout<<"size of _tagTest2: "<<sizeof(k2)<<endl;
    19      //看看内存模型
    20      k2.n1 = 1;
    21      k2.ch1 = 1;
    22      k2.f1 = 1.0f;
    23      memset(k2.szName , 1 , sizeof(k2.szName));
    24      k2.pTag = (_tagTest1*)&k2.n1;    //此处测试用,别纠结
    25 
    26  
    27      /*
    28      字节对齐下,
    29      int n1;                4
    30      char ch1;            1
    31      float f1;            4
    32      char szName[21];    21
    33      _tagTest1* pTag;    4
    34      总和为:34
    35      */
    36      _tagTest3 k3;
    37      cout<<"size of _tagTest3: "<<sizeof(k3)<<endl;
    38      //看看内存模型
    39      k3.n1 = 1;
    40      k3.ch1 = 1;
    41      k3.f1 = 1.0f;
    42      memset(k3.szName , 1 , sizeof(k3.szName));
    43      k3.pTag = (_tagTest1*)&k3.n1;    //此处测试用,别纠结
    44  
    45       system("pause");
    46  }

    实验结果输出:如分析所说的一样

    这时候问题来了,那么字节不对齐时在内存是怎样的呢...下面是字节不对齐时的内存截图

    下面的顺序清楚的对应,其中字节对齐的空位在内存里面补了cc,这个为什么本人没有深究,其他变量一目了然了,

    至于浮点数的内存模型为什么是这样,可以度娘一下,很多人分析了浮点数float的内存模型。

    ----------------------------------------------------------------------------------------------------------------------------

    ----------------------------邪恶的分割线------------------------------------------------------------------------------------

    2.0版本:

    鉴于上面有些地方不够清晰...现在再列出几个例子...例子来自网上摘下...

    1.在不对齐的情况下,拥有相同变量的结构最后得出的size也是不一样的..

    //定义两个结构,下面描述一下内存存放地址
    struct A
    {
       //假设内存地址从0开始...    
       int a;    //0-3
       char b; //4   
       short c;//6-7
    }
    //由于0-7的相加的结果为8...为自对齐4的倍数...
    //所以结果:sizeof(A) = 8
    
    //
    struct B
    {
         //假设内存地址从0开始... 
        char a;//0
        int b;  //4-7
        short c;//8-10
    }
    //由于0-10的相加的结果为11...不为自对齐4的倍数...补齐后为12
    //所以结果:sizeof(B) = 12
    

    2.再来使用Pragma手工更改了字节对齐值的情况,先看看Struct C的定义:

    #pragma pack(2)
    struct C
    {
        //假设从0开始
        char a;//0
        int b;//2-5
        short c;//6-7
    };
    sizeof(C)的答案为8
    

    Struct C的分析摘自网友总结:

     step 1: 确定结构体C对齐值:选择成员中最大的对齐值,即int a,对齐值为4         

     step 2: 确定手工指定对齐值,使用手工指定的值:2

     step 3: char a 的有效地址值=min(1,2),(因为0x0000%2=0),这样a的地址就是0x0000 

     step 4: int b 的有效对齐值=min(4,2),地址依次从0x0002~0x0005 (因为Ox0002%2=0)开始,分配4个字节,目前地址段分配情况就是:0x0000~0x0005    

     step 5: short c 的有效对齐值=min(2,2),由于要求考虑到对齐的情况,从0x0006(因为0x0006%2=0)开始,分配2个字节的地址0x0006~0x0007

     目前为止,地址段的分配情况就是:0x0000~0x0007共8个字节,同时也保证了Struct C的对齐情况(2字节对齐,pragma(2)),sizeof(C)=8

    结论:

     最后的最后补多一个混合的例子:

     1 struct tagS1
     2 {
     3     //假设地址从0开始,这里最长的类型为_unT1,长度为8...
     4     //变量的首地址为地址模sizeof(变量类型)结果为0的地址开始
     5     char a;//0 (0模1==0,所以从0开始)
     6     int n;//4-7 (2和3模4不等于0,从4开始)
     7     _unT1 t1;//8-15(8模8等于0,从8开始)
     8     long l;//16-19(16模4等于0,从16开始)
     9     char sz[22];//20-41(20模1等于0,从20开始)
    10 };
    11 //由于0-41的长度为42,42不为8的倍数,所以补长为8的倍数,结果为48
  • 相关阅读:
    Dockfile 使用 非root 用户运行容器
    Latex 小记
    Tmux 小技巧
    配置本地 overleaf
    arm板载ubuntu18.04系统安装QT4.8.7
    移植32位QT程序到ubuntu18.04
    TLS1.0禁用问题
    TLS1.0禁用问题
    Delphi程序“自杀”的有效办法
    Delphi7程序出现“EOSError code8-存储不足”问题的分析与解决
  • 原文地址:https://www.cnblogs.com/zhengfa-af/p/8329801.html
Copyright © 2011-2022 走看看