免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1037 | 回复: 0

sizeof的验证 [复制链接]

论坛徽章:
0
发表于 2009-12-25 10:34 |显示全部楼层

                                今天跟同事争论sizeof到底是编译时确定的值还是运行时确定的值,那么我们让我们用汇编来验证一下gcc的实现机制。
情形一:单个变量
验证程序:
               
               
                #include stdio.h>
int
main()
{
        int a;
        int b = sizeof(a);
        printf("%d\n", b);
}
gcc -O3 -S的结果:
1          .file   "t.c"
     2          .section        .rodata.str1.1,"aMS",@progbits,1
     3  .LC0:
     4          .string "%d\n"
     5          .text
     6          .p2align 4,,15
     7  .globl main
     8          .type   main, @function
     9  main:
    10          leal    4(%esp), %ecx
    11          andl    $-16, %esp
    12          pushl   -4(%ecx)
    13          pushl   %ebp
    14          movl    %esp, %ebp
    15          pushl   %ecx
    16          subl    $20, %esp
    17          movl    $4, 4(%esp)
    18          movl    $.LC0, (%esp)
    19          call    printf
    20          addl    $20, %esp
    21          popl    %ecx
    22          popl    %ebp
    23          leal    -4(%ecx), %esp
    24          ret
    25          .size   main, .-main
    26          .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
    27          .section        .note.GNU-stack,"",@progbits
注意第17行,编译时就把把变量在内存的大小4字节压栈了。
情形二:数组
验证程序:
#include stdio.h>
int
main()
{
        char a[10];
        int b = sizeof(a);
        printf("%d\n", b);
}
gcc -O3 -S的结果:         1          .file   "t.c"
     2          .section        .rodata.str1.1,"aMS",@progbits,1
     3  .LC0:
     4          .string "%d\n"
     5          .text
     6          .p2align 4,,15
     7  .globl main
     8          .type   main, @function
     9  main:
    10          leal    4(%esp), %ecx
    11          andl    $-16, %esp
    12          pushl   -4(%ecx)
    13          pushl   %ebp
    14          movl    %esp, %ebp
    15          pushl   %ecx
    16          subl    $20, %esp
    17          movl    $10, 4(%esp)
    18          movl    $.LC0, (%esp)
    19          call    printf
    20          addl    $20, %esp
    21          popl    %ecx
    22          popl    %ebp
    23          leal    -4(%ecx), %esp
    24          ret
    25          .size   main, .-main
    26          .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
    27          .section        .note.GNU-stack,"",@progbits
注意第17行,也是编译时就把数组的大小10压栈了。
情形三:可变长度数组
现在gcc支持可变长度数组了,情况要复杂一些了。测试程序:
#include stdio.h>
int
main(int argc, char **argv)
{
        int a[argc];
        int b = sizeof(a);
        printf("%d\n", b);
}
gcc -O3 -S的结果:         1          .file   "t.c"
     2          .section        .rodata.str1.1,"aMS",@progbits,1
     3  .LC0:
     4          .string "%d\n"
     5          .text
     6          .p2align 4,,15
     7  .globl main
     8          .type   main, @function
     9  main:
    10          leal    4(%esp), %ecx        #把第一个参数的地址放入ecx。main的第一个参数即argc的值,也就是我们数组的长度
    11          andl    $-16, %esp
    12          pushl   -4(%ecx)            #返回地址压栈
    13          pushl   %ebp                #建立stack frame
    14          movl    %esp, %ebp
    15          pushl   %ecx
    16          subl    $20, %esp
    17          movl    (%ecx), %edx         #取第一个参数的值,将其放入edx寄存器
    18          sall    $2, %edx             #edx算术左移两位,即乘4,这样就得到数组的大小
    19          leal    30(%edx), %eax       #以下给数组分配空间
    20          andl    $-16, %eax
    21          subl    %eax, %esp
    22          movl    %edx, 4(%esp)        #把保存在edx中的数组的大小压栈,准备调用sprintf打印数组大小
    23          movl    $.LC0, (%esp)
    24          call    printf
    25          movl    -4(%ebp), %ecx
    26          leave
    27          leal    -4(%ecx), %esp
    28          ret
    29          .size   main, .-main
    30          .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
    31          .section        .note.GNU-stack,"",@progbits
看上面的注释就可以很清楚的看到,数组的大小是在运行时计算得到的,而且数组的空间也是运行时动态调整的。
情形四:结构体
               
                #include stdio.h>
struct t{
        char a;
        int b;
};
int
main(int argc, char **argv)
{
        struct t a;
        int b = sizeof(a);
        printf("%d\n", b);
}
gcc -O3 -S的结果:         1          .file   "t.c"
     2          .section        .rodata.str1.1,"aMS",@progbits,1
     3  .LC0:
     4          .string "%d\n"
     5          .text
     6          .p2align 4,,15
     7  .globl main
     8          .type   main, @function
     9  main:
    10          leal    4(%esp), %ecx
    11          andl    $-16, %esp
    12          pushl   -4(%ecx)
    13          pushl   %ebp
    14          movl    %esp, %ebp
    15          pushl   %ecx
    16          subl    $20, %esp
    17          movl    $8, 4(%esp)
    18          movl    $.LC0, (%esp)
    19          call    printf
    20          addl    $20, %esp
    21          popl    %ecx
    22          popl    %ebp
    23          leal    -4(%ecx), %esp
    24          ret
    25          .size   main, .-main
    26          .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
    27          .section        .note.GNU-stack,"",@progbits
跟情形一和二类似,都是在17行就将结构体大小压栈。
总结
由以上的汇编程序可知,在gcc下,普通的变量,数组和结构体的大小都是在编译时就确定大小的,而可变长度数组是在运行时才能确定的。
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/6646/showart_2130395.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP