免费注册 查看新帖 |

Chinaunix

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

求助: 在if中定义的变量 [复制链接]

论坛徽章:
0
51 [报告]
发表于 2007-05-23 18:52 |只看该作者
原帖由 beepbug 于 2007-5-22 20:34 发表
两位版主注意自身形象,注意自己的身份。


晕。

论坛徽章:
0
52 [报告]
发表于 2007-05-23 20:38 |只看该作者
原帖由 koolcoy 于 2007-5-18 15:05 发表
像下面这样的代码如果这个if分枝没有被执行那么这个变量i是否存在? 我指的是物理上而不是逻辑上, 也就是这个i是不是动态分配的? (C语言, 不是C++)

  1. if (xxx) {
  2. int i;
  3. }
复制代码


首先,i 是一个自动变量,所以它的存储空间是自动分配的,而不是动态分配的(当然,也不是静态分配的)。

其次,你问的这个问题涉及到具体实现,而对同一段程序可能有多种实现方式,所以很难给出一个准确的答案。另外,“在物理上存在”的具体含义也值得商榷。

自动变量一般对应着进程的栈空间。在具体实现中多以函数为单位使用栈,也就是说:在编译的时候已经根据自动变量的数量和类型确定出了函数需要的栈空间,并确定了变量在此空间中的相对地址(或相对偏移)。这样,当程序执行到函数的时候,函数使用的栈空间已经被保留,相应地,自动变量的地址被确定。从这个意义上来说,似乎我们可以说这个变量在执行到函数的时候物理上已经存在了。

自动变量对应的栈空间也可能被同一函数中定义在不同块中的变量使用,所以物理上存在不意味着逻辑上也存在。

如果程序以块为单位组织栈,是不是我们就可以说只有进入变量作用域之后在物理上才存在?

自动变量 i 也有可能被编译器设置为寄存器变量。寄存器是始终存在的,那么这个自动变量什么时候在物理上存在?是进入作用域的时候、进入函数的时候、程序开始执行的时候、甚至程序尚未执行就已经存在了?

论坛徽章:
0
53 [报告]
发表于 2007-05-23 21:02 |只看该作者
LS非常好和全面的回答

论坛徽章:
0
54 [报告]
发表于 2007-05-23 22:08 |只看该作者
原帖由 思一克 于 2007-5-21 21:49 发表

[CODE]

#include <stdio.h>
main(int argc, char **argv)
{
int i;
  i = 123;
  if(argc) {
        int a[128];
        a[1] = 456;
  }
}



        .file   "tt.c ...


    这个例子是不恰当的,因为 argc 永远不会是0,所以 if(argc) 相当于 if(TRUE), 故int a[128]一定会执行到,因此编译器为它分配了空间。如果你把 if(argc) 改成 if(0) 再看看汇编,编译器是不会为它分配空间的。
    不仅如此,就算if条件式中的值是变量的话,如果开了优化选项编译器仍然不会为int a[128]分配空间,因为:1.如果在 if(xx){ int a[128]; a[1] = 456;} 这个范围之外引用了a, 编译器会在引用a的地方报错说变量未定义;2.如果在这个范围之外再没用到a, 就说明了a是没用的,对程序结果不会产生影响,编译器也会自动把int a[128]优化掉。
    综上,只有 if(TRUE) 时编译器才会分配空间,if(FALSE) 肯定不会分配,if(变量)时则要看是否开了优化选项,如果开了也基本会被优化掉,没开时才有可能分配。
    以上讨论基于 gcc4.1 , 其它的编译器可能有不同的处理...

论坛徽章:
0
55 [报告]
发表于 2007-05-23 22:33 |只看该作者
我觉得whyglinux和版主说的都比较有道理。

当然,如果非要“绝对正确”,看标准吧,而且现在存在的若干种计算机体系结构n,并不能假设n ! =无穷大。
标准没有规定的,一切皆有可能,但是如果这样讨论就是多余的了
不看汇编看c代码是不能确定的。 看汇编,看看i对应什么东西就知道了。

论坛徽章:
0
56 [报告]
发表于 2007-05-24 08:38 |只看该作者
那这个恰当吧。

if(argc) 和if(0) 不同。后者可以被编译优化掉。前者还没有。

一样的。i[128]是在函数(不是块)进入就分好的。




  1. main(int argc, char **argv)
  2. {
  3. int i = atol(argv[1]);
  4. int k = 123;
  5.   if(i) {
  6.     int i[128];
  7.         i[1] = 456;

  8.   }
  9. }


  10. main(int argc, char **argv)
  11. {
  12. int i = atol(argv[1]);
  13.         .file   "tabc.c"
  14.         .text
  15. .globl main
  16.         .type   main, @function
  17. main:
  18.         pushl   %ebp
  19.         movl    %esp, %ebp
  20.         subl    $536, %esp
  21.         andl    $-16, %esp
  22.         movl    $0, %eax
  23.         addl    $15, %eax
  24.         addl    $15, %eax
  25.         shrl    $4, %eax
  26.         sall    $4, %eax
  27.         subl    %eax, %esp
  28.         subl    $12, %esp
  29.         movl    12(%ebp), %eax
  30.         addl    $4, %eax
  31.         pushl   (%eax)
  32.         call    atol
  33.         addl    $16, %esp
  34.         movl    %eax, -12(%ebp)
  35.         movl    $123, -16(%ebp)
  36.         cmpl    $0, -12(%ebp)
  37.         je      .L2
  38.         movl    $456, -532(%ebp)
  39. .L2:
  40.         leave
  41.         ret
  42.         .size   main, .-main
  43.         .section        .note.GNU-stack,"",@progbits
  44.         .ident  "GCC: (GNU) 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)"
复制代码



原帖由 fedora_core_7 于 2007-5-23 22:08 发表


    这个例子是不恰当的,因为 argc 永远不会是0,所以 if(argc) 相当于 if(TRUE), 故int a[128]一定会执行到,因此编译器为它分配了空间。如果你把 if(argc) 改成 if(0) 再看看汇编,编译器是不会为它分配空 ...

论坛徽章:
0
57 [报告]
发表于 2007-05-24 09:16 |只看该作者
这个问题我觉得意义不大
1,C89不支持这种定义方式
2,即使支持这种方式,具体编译器的实现也有出入,
虽然是仅仅作用空间才有效,但是在栈中分配的时间,或许在进入该函数的时候就分配了。这个标准C没有定义的~

论坛徽章:
0
58 [报告]
发表于 2007-05-24 09:22 |只看该作者
本来意义不大。但是该帖子也有学习编译代码产生机理的作用。可以帮助深入了解C

C标准没有定义。所以现有的答案就是上面的。有反例,可以举出。

原帖由 shmilylxx 于 2007-5-24 09:16 发表
这个问题我觉得意义不大
1,C89不支持这种定义方式
2,即使支持这种方式,具体编译器的实现也有出入,
虽然是仅仅作用空间才有效,但是在栈中分配的时间,或许在进入该函数的时候就分配了。这个标准C没有定义的~

论坛徽章:
0
59 [报告]
发表于 2007-05-24 15:38 |只看该作者
1)同为动态分配的堆分配和栈分配有很大的区别。在程序启动时,还没有堆分配,虚的实的,都没有。但是,加载器为栈空间做了一次性的虚空间分配,大小是从用户空间最高端到链接器确定的栈下限。在程序运行期间,这个没有变化。但是,只向系统申请了一页物理内存。因为至少要存放环境变量等。如果以后这一页用完了,就再申请一页。弹出多了,可能会回收一页实存。
前面一位说得对,有的东西物理上存在,逻辑上却当它没有了。压入一个元素,再把它弹出,物理上它还在,可逻辑上当它没有了。
2)我还是认为,对这个问题来说,看C码,看汇编码,看机器码,是一回事。本来在C码有的东西,编译后,在汇编码里当然也存在。否则是被编译器贪污了。
但是,程序里出现的东西,进程里并一定出现。光看汇编,不能得出结论。
但是,也不绝对排除未用到的东西出现在进程里。前面说的并行计算也算一个例子。

论坛徽章:
0
60 [报告]
发表于 2007-05-24 15:56 |只看该作者
“光看汇编,不能得出结论。”

就事论事,单就这个问题,光看LINUX I386 GCC汇编,不能得出其上的结论吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP