免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123
最近访问板块 发新帖
楼主: liexusong
打印 上一主题 下一主题

关于局部变量 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2010-10-10 17:09 |只看该作者
看汇编也可以了解一些问题,但是你不能了解全部问题.
例如这里你可以了解到为什么每次地址都是相同的.
但是你不能了解编译器为什么会这么处理.
C语言没有规定不许块变量使用同一块内存.循环一次就出了块的作用域,当如再次进入的时复用这个地址有何不可?
这个是编译器去发挥处理的地方.而不是C语言规定的地方.

论坛徽章:
0
22 [报告]
发表于 2010-10-10 17:10 |只看该作者
看汇编也可以了解一些问题,但是你不能了解全部问题.
例如这里你可以了解到为什么每次地址都是相同的.
但是 ...
davelv 发表于 2010-10-10 17:09



    学习了.

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
23 [报告]
发表于 2010-10-10 17:19 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
24 [报告]
发表于 2010-10-11 09:48 |只看该作者
  1. #include <stdio.h>

  2. struct mystruct {
  3.         int i;
  4. };

  5. int main()
  6. {
  7.         int i;
  8.         
  9.         for (i = 0; i < 10; i++) {
  10.                 if (i%2)
  11.                 {
  12.                    int i;
  13.                    printf("i-------%p\n", &i);
  14.                 }
  15.                 struct mystruct s;
  16.                
  17.                 s.i = i;
  18.                 printf("s-------%p\n", &s);
  19.         }
  20.         
  21.         return 0;
  22. }
复制代码

论坛徽章:
0
25 [报告]
发表于 2010-10-15 19:58 |只看该作者
回复 1# liexusong


本人在以下平台做了一点分析:
$ uname -a
Linux laptop 2.6.32-23-generic #37-Ubuntu SMP Fri Jun 11 08:03:28 UTC 2010 x86 64 GNU/Linux
$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

我们知道,一个典型的的 C 程序运行于 unix-like 机器上时,其进程中的内存布局如图2所示。由图可知,栈空间是向低地址扩展的,main 函数的局部变量 i,s 等就存储在栈空间中。为了对 s 的生命周期一探究竟,可以使用 “gcc -S test.c” 来生成汇编代码,得到的输出文件如图3所示。
  1.     .file    "test.c"
  2.     .section    .rodata
  3. .LC0:
  4.     .string    "%p\n"
  5.     .text
  6. .globl main
  7.     .type    main, @function
  8. main:
  9. .LFB0:
  10.     .cfi_startproc
  11.     pushq    %rbp
  12.     .cfi_def_cfa_offset 16
  13.     movq    %rsp, %rbp
  14.     .cfi_offset 6, -16
  15.     .cfi_def_cfa_register 6
  16.     subq    $16, %rsp
  17.     movl    $0, -4(%rbp)
  18.     jmp    .L2
  19. .L3:
  20.     movl    -4(%rbp), %eax
  21.     movl    %eax, -16(%rbp)
  22.     leaq    -16(%rbp), %rax
  23.     movq    %rax, %rsi
  24.     movl    $.LC0, %edi
  25.     movl    $0, %eax
  26.     call    printf
  27.     addl    $1, -4(%rbp)
  28. .L2:
  29.     cmpl    $9, -4(%rbp)
  30.     jle    .L3
  31.     movl    $0, %eax
  32.     leave
  33.     ret
  34.     .cfi_endproc
  35. .LFE0:
  36.     .size    main, .-main
  37.     .ident    "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
  38.     .section    .note.GNU-stack,"",@progbits
复制代码
图3  对应的汇编代码

   图3代码中,第 11,13 行建立 main 函数的栈帧,程序运行到这里后,%rbp 指向 main 函数帧起始地址,并且此时 main 函数栈帧为空。第 16 行在 main 函数栈帧中分配了 16 个字节,第 17 行的运行结果相当于将 i 存储在栈帧起始地址减 4 的位址并且将其初始化为 0。此时的 main 函数栈帧如图4。



  接下来,程序在第 18 行跳转到循环体的判断条件(第 29 行),第 20 行至 27 行为循环体。在循环体中,第 20 行,21 行通过%eax 作为中介,将 i 的值(注意 i 存储在 main 栈帧起始地址减 4 的位地址,见图4)赋给某一个变量,而该变量的地址为%rbp(也就是帧起始地址)减 16。对照图1中的 C 代码,可以猜测该变量为 s.i。程序第 22 行证实了我们的猜测,这条指令是取前面这个变量的地址。上面的分析中,我们不加区分的对待&s 与&s.i,这是因为在 C 中,结构体对象的第一个成员地址与结构体对象的地址是一样的。
   程序第 26 行调用系统函数 printf,第 27 行将 i 加 1,第 29 行执行循环的条件判断,第 30 行根据判断的结果产生相应的跳转,第 31 行准备函数返回值,第 32 行释放 main 函数栈帧所占用的内存,第 33 行 main 函数返回。
   通过以上分析可知,第 16 行分配了 16 个字节以后,一直到 main 函数返回前(第 32 行),指向栈顶的指针(寄存器%rsp)都没有变化,因此在栈内也就没有内存的分配与释放,从而使图1 中的代码编译后打印相同的地址。
  至于导致上述结果(块中的局部变量在进入块之前分配),我们可以认为是编译器优化的结果。但是,如果程序每一轮循环都为 s 重新分配和释放内存,对照图4可知,程序将在进入循环体时,下移栈指针(即将%rsp 减某固定值),退出循环体之前,栈指针回到初始值,可以想象,这样运行的结果,程序仍将打印相同的地址值。由此可见,局部变量的生命期更多的是一种编译期行为(在生成汇编代码之前),其作用是让编译器帮助程序员检察代码的合法性。当然,上面的分析仅限于 linux 下的 gcc 平台,其他平台可以同理分析,但不一定有相同的结果。

论坛徽章:
0
26 [报告]
发表于 2010-10-16 18:52 |只看该作者
你的结论没问题。
    问题是我觉得编程时不能依赖你所观察到的“花括号仅仅是限定内部定义的变 ...
pmerofc 发表于 2010-10-10 16:25



    “花括号仅仅是限定内部定义的变量外部不可见” 这个结论并非根据汇编得出的结论,相反我过去在不太成熟的思考中根据“程序块内部定义的变量外部不可见”想当然地得到一个错误结论:编译器对于局部变量处理,在程序块开始的时候压栈,并在离开程序块的时候退栈。而这段汇编代码推翻了我过去得到的结论。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
27 [报告]
发表于 2010-10-16 19:14 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP