zoukankan      html  css  js  c++  java
  • c/c++ 字节对齐

    c 字节对齐

    概念:

    结构体里会包括各种类型的成员,比如int char long等等,它们要占用的空间不同,系统为一个结构体开辟内存空间时,会有2种选择。

    • 第一种:节省空间的方案,以上面的列子来说的话,就是4(int) + 1(char) + 8(long) =13个字节;
    • 第二种:浪费空间的方案,以上面的列子来说的话,就是4(int) + 4(char) + 8(long) =16个字节;

    其实,系统是用的第二种方案。

    字节对齐的目的:

    为了CPU只寻找地址一次,就能够把目标内存中的数据取出来。

    现代计算机中内存空间都是按照byte划分的 ,如果是用第一种节省空间的方案,为了要取一个int或者long的成员的值,CPU寻址一次,可能只取出来一部分,所以需要再次寻址,这样就导致CPU的效率降低。为了提高CPU的效率,所以选择牺牲空间,但是节省了时间。

    经验总结

    声明结构体成员的时候,一定把占用空间最小的类型放在最前面,占用空间最大的放在最后面,这样就会节省内存空间。

    程序验证

    #include <stdio.h>
    
    typedef struct A{
      char a;
      char b;
      char c;
    }A;
    //#pragma pack(4) //如果把注释打开就是强制按4字节对齐,所以就是16
    typedef struct B{//24
      int a;//占用4字节 + 4 //往下看,下面的8字节,所以补4个字节
      long b;//占用8字节
      char c;//占用1字节+ 7 // 4+4+8+1=9,但9不是8的倍数,所以在最后的char c处加7个字节
    }B;
    typedef struct C{//16
      char a;//1 + 3
      int b;//4
      long c;//8
    }C;
    struct D{//32
      int a;//4 + 4 //往下看,下面的8字节,所以补4个字节
      struct S1{//16
        long b;//8
        char c;//1 + 1 //往下看,下面的2字节,所以补1个字节
        short d;//2 + 4 //8+2+2=12但不是8的倍数,所以在最后的short d处加4个字节
      } aa;
      int e;//4 + 4 //8+16+4=28但不是8的倍数,所以在最后的int e处加4个字节
    }D;
    struct E{//40
      int a;//4 + 4
      struct S2{//24
        short d;//2 + 6 //往下看,下面的8字节,所以补6个字节
        long b;//8
        char c;//1 + 7 //8+8+1=17但不是8的倍数,所以在最后的char c处加7个字节
      } aa;
      int e;//4 + 4 ////8+24+4=36但不是8的倍数,所以在最后的int e处加4个字节
    }E;
    struct F{//72
      int a;//4 + 4
      struct {//56
        short d[20];//40 //不管数组里多少个元素,只看数组的类型
        long b;//8
        char c;//1 + 7
      } ;
      int e;//4 + 4
    }F;
    
    int main(){
      printf("A size = %ld
    ",sizeof(A));
      printf("B size = %ld
    ",sizeof(B));
      printf("C size = %ld
    ",sizeof(C));
      printf("D size = %ld
    ",sizeof(D));
      printf("E size = %ld
    ",sizeof(E));
      printf("F size = %ld
    ",sizeof(F));
      B B1;
      B1.a = 10;
      B1.b = 12;
      B1.c = 'A';
    }
    

    运行结果:

    A size = 3
    B size = 24
    C size = 16
    D size = 32
    E size = 40
    F size = 72
    

    位域

    变量可以按比特位进行定义,比如定义只占用1个比特位的char c:1;

    只占用10个比特位的int i:10;

    **定义的比特位不可以超过类型自身所占用的字节数 **

    int i:33;//编译不过,因为int占用4个字节,32个比特位,所以最多定义到int i:32;

    #include <stdio.h>
    
    struct A{//char占用1个字节8个比特位,a b c各占用1个比特位,总共3个比特位,小于8个比特位,所以这个结构体占用1个字节
      char a:1;
      char b:1;
      char c:1;
    }A;
    struct B{//char占用1个字节8个比特位,a b c总共占用8个比特位,正好是1个字节,所以这个结构体占用1个字节
      char a:2;
      char b:2;
      char c:4;
    }B;
    struct B1{//char占用1个字节8个比特位,a b c总共占用9个比特位,超过1个字节,所以这个结构体占用2个字节
      char a:2;
      char b:2;
      char c:5;
    }B1;
    struct C{//int占用4个字节32个比特位,a b总共占用32个比特位,正好4个字节,所以这个结构体占用4个字节
      int a:31;
      char b:1;
    }C;
    struct C1{//int占用4个字节32个比特位,a b总共占用33个比特位,超过4个字节,所以这个结构体占用8个字节,因为在char b处需要补3个字节
      int a:31;
      char b:2;
    }C1;
    struct C2{//即使结构体C2看起来只占用3个比特位,但是成员a是int类型,所以这个结构体占用4个字节
      int a:1;
      char b:2;
    }C2;
    
    int main(){
      printf("A:%ld
    ", sizeof(A));
      printf("B:%ld
    ", sizeof(B));
      printf("B1:%ld
    ", sizeof(B1));
      printf("C:%ld
    ", sizeof(C));
    
      //结构体C里的成员a占用32个比特位的后31个比特位;成员b占用第1个比特位
      struct C sc;
      sc.a =10;
      sc.b = 1;
    }
    GDB的调试结果:
    40	  sc.a =10;
    (gdb) p &sc//打印出sc.a的地址
    $1 = (struct C *) 0x7fffffffdecc
    (gdb) x/tw 0x7fffffffdecc//用二进制方式,产看内存地址里的值
    0x7fffffffdecc:	00000000000000000000000000000000
    (gdb) n
    41	  sc.b = 1;
    (gdb) x/tw 0x7fffffffdecc//发现10被放到内存中了,1010就是十进制的10
    0x7fffffffdecc:	00000000000000000000000000001010
    (gdb) n
    42	}
    (gdb) x/tw 0x7fffffffdecc//发现1被放到内存的第一个比特位上了
    0x7fffffffdecc:	10000000000000000000000000001010
    
    

    运行结果:

    A:1
    B:1
    B1:2
    C:4
    C1:8
    C2:4
    
  • 相关阅读:
    JS自定义功能函数实现动态添加网址参数修改网址参数值
    伍、ajax
    类的静态方法(函数)中为什么不能调用非静态成员(属性)?
    android 数据存储 SharePreferences 简单使用
    实现多线程的方式
    线程、进程概念与Android系统组件的关系
    通知—Notifications
    活动栏—Action Bar
    Android菜单—Menu
    对话框控件—Dialog
  • 原文地址:https://www.cnblogs.com/xiaoshiwang/p/9187808.html
Copyright © 2011-2022 走看看