zoukankan      html  css  js  c++  java
  • 本机尺寸与结构体对齐

    本机尺寸

    如果本机是32位的,那么对32位的支持是最好的

    在很多的书上都能看到类似这样的代码

    #include<stdio.h>
    void Function(char x,char y)
    {
        char c=x+y;
    }
    void main()
    {
        char a=1;
        char b=2;
        Function(a,b);
    }

    我们通过反汇编会发现

    1:    #include<stdio.h>
    2:    void Function(char x,char y)
    3:    {
    00401020   push        ebp
    00401021   mov         ebp,esp
    00401023   sub         esp,44h
    00401026   push        ebx
    00401027   push        esi
    00401028   push        edi
    00401029   lea         edi,[ebp-44h]
    0040102C   mov         ecx,11h
    00401031   mov         eax,0CCCCCCCCh
    00401036   rep stos    dword ptr [edi]
    4:        char c=x+y;
    00401038   movsx       eax,byte ptr [ebp+8]
    0040103C   movsx       ecx,byte ptr [ebp+0Ch]
    00401040   add         eax,ecx
    00401042   mov         byte ptr [ebp-4],al
    5:    }
    00401045   pop         edi
    00401046   pop         esi
    00401047   pop         ebx
    00401048   mov         esp,ebp
    0040104A   pop         ebp
    0040104B   ret
    --- No source file  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    0040104C   int         3
    0040104D   int         3
    0040104E   int         3
    0040104F   int         3
    --- C:WindowsSystem32a.cpp  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    6:    void main()
    7:    {
    00401050   push        ebp
    00401051   mov         ebp,esp
    00401053   sub         esp,48h
    00401056   push        ebx
    00401057   push        esi
    00401058   push        edi
    00401059   lea         edi,[ebp-48h]
    0040105C   mov         ecx,12h
    00401061   mov         eax,0CCCCCCCCh
    00401066   rep stos    dword ptr [edi]
    8:        char a=1;
    00401068   mov         byte ptr [ebp-4],1
    9:        char b=2;
    0040106C   mov         byte ptr [ebp-8],2
    10:       Function(a,b);
    00401070   mov         al,byte ptr [ebp-8]
    00401073   pusheax
    00401074   mov         cl,byte ptr [ebp-4]
    00401077   pushecx
    00401078   call        @ILT+0(Function) (00401005)
    0040107D   add         esp,8
    11:   }
    00401080   pop         edi
    00401081   pop         esi
    00401082   pop         ebx
    00401083   add         esp,48h
    00401086   cmp         ebp,esp
    00401088   call        __chkesp (004010a0)
    0040108D   mov         esp,ebp
    0040108F   pop         ebp
    00401090   ret

    蓝色部分是传递进去的参数

    然后我们发现,尽管定义的是char类型,压栈的却是eax而并不是al。

    在32位的系统中,系统默认最合适的数据类型,就是32个bit,即4字节。同理,64位的系统就是8字节。

    也就是说,如果使用小于4个字节的局部变量来进行参数传递,vc编译器仍然会按照4个字节来进行传递,但是多余的部分并不会使用。

    从上面我们能看到,当创建一个小于4字节局部变量时,编译器为我们分配的内存空间为0x44。

    当我们创建两个局部变量时

    1:    #include<stdio.h>
    2:    void Function(char x,char y)
    3:    {
    00401020   push        ebp
    00401021   mov         ebp,esp
    00401023   sub         esp,44h
    00401026   push        ebx
    00401027   push        esi
    00401028   push        edi
    00401029   lea         edi,[ebp-44h]
    0040102C   mov         ecx,11h
    00401031   mov         eax,0CCCCCCCCh
    00401036   rep stos    dword ptr [edi]
    4:        char c=x+y;
    00401038   movsx       eax,byte ptr [ebp+8]
    0040103C   movsx       ecx,byte ptr [ebp+0Ch]
    00401040   add         eax,ecx
    00401042   mov         byte ptr [ebp-4],al
    5:        char d;
    6:    }
    00401045   pop         edi
    00401046   pop         esi
    00401047   pop         ebx
    00401048   mov         esp,ebp
    0040104A   pop         ebp
    0040104B   ret
    --- No source file  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    0040104C   int         3
    0040104D   int         3
    0040104E   int         3
    0040104F   int         3
    --- C:WindowsSystem32a.cpp  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    7:    void main()
    8:    {
    00401050   push        ebp
    00401051   mov         ebp,esp
    00401053   sub         esp,48h
    00401056   push        ebx
    00401057   push        esi
    00401058   push        edi
    00401059   lea         edi,[ebp-48h]
    0040105C   mov         ecx,12h
    00401061   mov         eax,0CCCCCCCCh
    00401066   rep stos    dword ptr [edi]
    9:        char a=1;
    00401068   mov         byte ptr [ebp-4],1
    10:       char b=2;
    0040106C   mov         byte ptr [ebp-8],2
    11:       Function(a,b);
    00401070   mov         al,byte ptr [ebp-8]
    00401073   push        eax
    00401074   mov         cl,byte ptr [ebp-4]
    00401077   push        ecx
    00401078   call        @ILT+0(Function) (00401005)
    0040107D   add         esp,8
    12:   }
    00401080   pop         edi
    00401081   pop         esi
    00401082   pop         ebx
    00401083   add         esp,48h
    00401086   cmp         ebp,esp
    00401088   call        __chkesp (004010a0)
    0040108D   mov         esp,ebp
    0040108F   pop         ebp
    00401090   ret

    缓冲区变为0x48了

    再尝试创建一个大于4字节的数

    1:    #include<stdio.h>
    2:    void Function(char x,char y)
    3:    {
    00401020   push        ebp
    00401021   mov         ebp,esp
    00401023   sub         esp,4Ch
    00401026   push        ebx
    00401027   push        esi
    00401028   push        edi
    00401029   lea         edi,[ebp-4Ch]
    0040102C   mov         ecx,13h
    00401031   mov         eax,0CCCCCCCCh
    00401036   rep stos    dword ptr [edi]
    4:        char c=x+y;
    00401038   movsx       eax,byte ptr [ebp+8]
    0040103C   movsx       ecx,byte ptr [ebp+0Ch]
    00401040   add         eax,ecx
    00401042   mov         byte ptr [ebp-4],al
    5:        __int64 d;
    6:    }
    00401045   pop         edi
    00401046   pop         esi
    00401047   pop         ebx
    00401048   mov         esp,ebp
    0040104A   pop         ebp
    0040104B   ret
    --- No source file  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    0040104C   int         3
    0040104D   int         3
    0040104E   int         3
    0040104F   int         3
    --- C:WindowsSystem32a.cpp  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    7:    void main()
    8:    {
    00401050   push        ebp
    00401051   mov         ebp,esp
    00401053   sub         esp,48h
    00401056   push        ebx
    00401057   push        esi
    00401058   push        edi
    00401059   lea         edi,[ebp-48h]
    0040105C   mov         ecx,12h
    00401061   mov         eax,0CCCCCCCCh
    00401066   rep stos    dword ptr [edi]
    9:        char a=1;
    00401068   mov         byte ptr [ebp-4],1
    10:       char b=2;
    0040106C   mov         byte ptr [ebp-8],2
    11:       Function(a,b);
    00401070   mov         al,byte ptr [ebp-8]
    00401073   push        eax
    00401074   mov         cl,byte ptr [ebp-4]
    00401077   push        ecx
    00401078   call        @ILT+0(Function) (00401005)
    0040107D   add         esp,8
    12:   }
    00401080   pop         edi
    00401081   pop         esi
    00401082   pop         ebx
    00401083   add         esp,48h
    00401086   cmp         ebp,esp
    00401088   call        __chkesp (004010a0)
    0040108D   mov         esp,ebp
    0040108F   pop         ebp
    00401090   ret

    这里就变成0x4c,因为__int64是8位的,所以就是0x48+4=0x4c了。

    总结:

    0x00.在32位系统上创建小于32位的局部变量是不合适的,在空间分配时仍然会按照32位来进行分配。但多余部分并不会使用。所以尽量避免使用小于32位的局部变量。

    0x01.在vc6.0中调用函数时,每创建一个小于32位的局部变量,就会分配4个字节的空间。如果创建大于32位的局部变量,就会分配该局部变量实际的空间。

    总的来说就是一句话,在32位的windows系统,使用vc6编程时尽量不要创建小于4个字节的局部变量,整数类型的参数,一律int类型。

    结构体对齐

    在计算机中,结构体通常是字节对齐的。这样在数据的存储方面能达到最好的效率。空间和时间的取舍问题~~~

    例子:

    1:

    #include<stdio.h>
    struct test
    {
        char a;
        int b;
        char c;
    };
    int main()
    {
        printf("%d",sizeof(test));
        return 0;
    }

    2.

    #include<stdio.h>
    struct test
    {
        int b;
        char a;
        char c;
    };
    int main()
    {
        printf("%d",sizeof(test));
        return 0;
    }

    此时,前者打印出来的大小是12,而后者打印的结果却是8。

    如果想控制这个对齐字节可以通过加上两行代码。

    1 #pragma pack(1)
    2 struct Test
    3 {
    4     int a;
    5     __int64 b;
    6     char c;
    7 }
    8 #pragma pack()

    此时对齐的字节就是1了。

    那么当不写#pragma时,又是对齐的字节又是多少呢?

    这是和编译器有关系。比如我使用的是vc6.0,可以在这里看到:

    不建议修改这里参数。

    结构体对齐又可以叫字节对齐。大致遵循以下四个原则。

    原则1:数据成员对齐规则,结构的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍开始存储)
    原则2:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足要补齐。
    原则3:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double 等元素,那b应该从8的整数倍开始存储)
    原则4:对齐参数如果比结构体成员的sizeof值小,该成员的偏移量应该以此值为准。也就是说,结构体成员的偏移量应该取二者的最小值

    其实很好理解,随便一个例子。

    struct test
    {
        int b;
        char a;
        char c;
    };

    这个就相当于这样。所以这个是8。

    再来一个,同样还是上文中提到的。

    struct test
    {
        char a;
        int b;
        char c;
    };

    总的来说。一个结构体中,所占空间最大的类型,和对齐字节比较。取较小的,记为x。然后该结构体第一个成员记为s1,第二个记为s2。。。。。

    然后x-s1与s2比较,小于的话重新加一个x,另起一行,而第一个成员的后面就空着浪费掉了,被填充上数据cc,即int3。大于的话则变为x-s1-s2与s3比较。(自己理解的)

    所以会有,结构体大小一定是最大成员大小的整数倍。

    那么加入一个结构体中有另一个结构体该如何计算。

    #include<stdio.h>
    struct test1
    {
        int a;
        char b;
    };
    struct test2
    {
        test1 a;
        int b;
    };
    int main()
    {
        printf("%d",sizeof(test2));
        return 0;
    }

    结果仍然是12。

    这是因为test2实际就相当于这样一个结构体。(仍然是自己的理解,不过感觉是对的~~~错误欢迎指出)

    struct test2
    {
        int a;
        char b;
        int c;
    };
  • 相关阅读:
    spring的学习____9.spring aop的实现方式 2 :通过自定义类实现Aop
    spring的学习____8 spring_AoP的实现方式一:使用spring API实现
    Spring 的学习报错_____2.空指针异常 java.lang.NullPointerException
    Spring学习的报错____1.Type interface com.xbf.dao.UserDao is not known to the MapperRegistry.
    spring的学习7_____AoP(面向切面)概述
    Spring 的学习6_______静态代理和动态代理(AOP的底层实现原理)
    Spring的学习____5.Bean的作用域
    Spring的学习____3.spring配置文件的解析
    第四课--程序的控制结构
    第三课--文本进度条实现
  • 原文地址:https://www.cnblogs.com/zimudao/p/8505530.html
Copyright © 2011-2022 走看看