像下面这样的代码如果这个if分枝没有被执行那么这个变量i是否存在? 我指的是物理上而不是逻辑上, 也就是这个i是不是动态分配的? (C语言, 不是C++)
if (xxx) {
int i;
}
gaocheng 回复于:2007-05-18 15:21:21
该变量在栈中,未被执行只是不妨问该地址就是了。
思一克 回复于:2007-05-18 15:21:41
存在。
不是临时用到动态分配的。
在LINUX GCC如此。其它应该同。
tyc611 回复于:2007-05-18 16:56:05
如果不进入条件分支,就不存在,它的生存期在块内
思一克 回复于:2007-05-18 16:59:42
你看书的结论不算。应该看程序(汇编)。
生存其在整个函数中。(LINUX/GCC)
引用:原帖由 tyc611 于 2007-5-18 16:56 发表
如果不进入条件分支,就不存在,它的生存期在块内
weckay 回复于:2007-05-18 17:00:49
又学到一点~
missjiang 回复于:2007-05-18 17:10:27
林妹妹永远的离开了我们 . . . . . .
tyc611 回复于:2007-05-18 17:12:00
引用:原帖由 思一克 于 2007-5-18 16:59 发表
你看书的结论不算。应该看程序(汇编)。
生存其在整个函数中。(LINUX/GCC)
那只是编译的具体实现了,说明该编译器没有将活动记录做到块(可能考虑到效率问题吧)
思一克 回复于:2007-05-18 17:12:49
局部变量都有自己的生存期. . . . . .
引用:原帖由 missjiang 于 2007-5-18 17:10 发表
林妹妹永远的离开了我们 . . . . . .
高峰 回复于:2007-05-18 17:44:39
:em06::em06::em06::em06::em06:
林妹妹都出来了!
MMMIX 回复于:2007-05-18 17:49:23
引用:原帖由 思一克 于 2007-5-18 16:59 发表
你看书的结论不算。应该看程序(汇编)。
生存其在整个函数中。(LINUX/GCC)
同时还应该看标准
思一克 回复于:2007-05-18 20:06:35
哪里有标准规定这个?
我没有找过. 如果你知道, 可以共享贴
koolcoy 回复于:2007-05-18 21:11:44
引用:原帖由 missjiang 于 2007-5-18 17:10 发表
林妹妹永远的离开了我们 . . . . . .
消息真灵通
MMMIX 回复于:2007-05-18 22:18:58
引用:原帖由 思一克 于 2007-5-18 20:06 发表
哪里有标准规定这个?
我没有找过. 如果你知道, 可以共享贴
这个可以参考 C99 的
6.2.1 Scopes of identifiers 和 6.8.2 Compound statement
mik 回复于:2007-05-18 22:33:28
即使能动态生成变量,效率也不会高
adslxu 回复于:2007-05-18 23:24:27
我觉得也在栈中
beepbug 回复于:2007-05-20 08:37:03
引用:原帖由 思一克 于 2007-5-18 16:59 发表
你看书的结论不算。应该看程序(汇编)。
生存其在整个函数中。(LINUX/GCC)
看汇编不说明问题。看C,和看汇编,都是在看代码的静态。只不过一个是在高级语言层面,一个是在低级语言层面罢了。
而楼主问的是,这代码在运行时,有没有 i 这个实体生成?
我想,应该if为true时,才在栈里生成,并在代码段结束时弹出消失。
mik 回复于:2007-05-20 08:46:41
引用:原帖由 beepbug 于 2007-5-20 08:37 发表
看汇编不说明问题。看C,和看汇编,都是在看代码的静态。只不过一个是在高级语言层面,一个是在低级语言层面罢了。
而楼主问的是,这代码在运行时,有没有 i 这个实体生成?
我想,应该if为true时,才在栈 ...
:em06: 你了解过? 请你讲一讲,在true时,如何生成实体, false 时去掉实体?
beepbug 回复于:2007-05-20 09:51:38
引用:原帖由 mik 于 2007-5-20 08:46 发表
:em06: 你了解过? 请你讲一讲,在true时,如何生成实体, false 时去掉实体?
你仔细看看我的回帖。我没说过“在true时,如何生成实体, false 时去掉实体”。
在楼主给出的代码:
if (xxx) {
int i;
}
里,如果xxx为true,后面的{}才被执行。{后,栈里为i开了4字节的单元(如果是32位机的话)。遇}时,这四个字节被弹出。
另外,请注意你的说话。开口就是“你了解过?”,版民在这里回帖,是不是先要具结保证“了解过”?
JohnBull 回复于:2007-05-20 10:05:38
引用:原帖由 beepbug 于 2007-5-20 09:51 发表
如果xxx为true,后面的{}才被执行。{后,栈里为i开了4字节的单元(如果是32位机的话)。遇}时,这四个字节被弹出。
这要看在这个标准中,变量定义是否被看作普通语句了。
照你的说法,汇编源码中必然有根据条件对ESP进行调整的代码了,而实际上呢?
你只要自己写一段测试代码,去不同平台,用不同语言标准编译成汇编代码,看看就知道了。
请帖出测试结果再进一步发言。
福瑞哈哥 回复于:2007-05-20 13:49:12
什麼叫動態變量?-- 寄存器變量? 還是堆變量?
思一克 回复于:2007-05-20 14:38:29
通过看汇编已经给LZ了LINUX GCC的正确答案. 在其它平台上也应该一样,如果有不一样,请给出例证.
什么事情不要平想象. 要自己实验.
引用:原帖由 beepbug 于 2007-5-20 08:37 发表
看汇编不说明问题。看C,和看汇编,都是在看代码的静态。只不过一个是在高级语言层面,一个是在低级语言层面罢了。
而楼主问的是,这代码在运行时,有没有 i 这个实体生成?
我想,应该if为true时,才在栈 ...
beepbug 回复于:2007-05-20 16:43:22
引用:原帖由 JohnBull 于 2007-5-20 10:05 发表
这要看在这个标准中,变量定义是否被看作普通语句了。
照你的说法,汇编源码中必然有根据条件对ESP进行调整的代码了,而实际上呢?
你只要自己写一段测试代码,去不同平台,用不同语言标准编译成汇编代码 ...
你先看清楼主的发帖:
像下面这样的代码如果这个if分枝没有被执行那么这个变量i是否存在? 我指的是物理上而不是逻辑上, 也就是这个i是不是动态分配的? (C语言, 不是C++)
再发言,好不好?至少先看清别人说的,再教训人,好不好?
据我理解,楼主说的是“执行”,也就是关于进程的问题。你看的,和你要求别人看的,是汇编代码,那是关于程序的。程序和进程是两码事,前者是静态的概念,后者是动态的概念。扯在一起,就变成鸡说鸭说了。
不过你说“去不同平台”,这有道理。我曾看见一篇关于并行计算的论文,说为了提高运行效率,遇分支时,条件判断,true分支、false分支,各引发一个线程来跑,再根据条件判断,来选择两个分支结果中的一个。在这样的平台上,i 总是会生成。
MMMIX 回复于:2007-05-20 16:52:39
引用:原帖由 beepbug 于 2007-5-20 16:43 发表
像下面这样的代码如果这个if分枝没有被执行那么这个变量i是否存在? 我指的是物理上而不是逻辑上, 也就是这个i是不是动态分配的? (C语言, 不是C++)
再发言,好不好?至少先看清别人说的,再教训人,好不好?
据我理解,楼主说的是“执行”,也就是关于进程的问题。你看的,和你要求别人看的,是汇编代码,那是关于程序的。程序和进程是两码事,前者是静态的概念,后者是动态的概念。扯在一起,就变成鸡说鸭说了。
楼主的问题扯不上进程。
[ 本帖最后由 MMMIX 于 2007-5-20 16:54 编辑 ]
mik 回复于:2007-05-20 17:10:56
引用:原帖由 beepbug 于 2007-5-20 16:43 发表
你先看清楼主的发帖:
像下面这样的代码如果这个if分枝没有被执行那么这个变量i是否存在? 我指的是物理上而不是逻辑上, 也就是这个i是不是动态分配的? (C语言, 不是C++)
再发言,好不好?至少先看清别人 ...
他已经说得很明白了.
这是你说的:
引用:我想,应该if为true时,才在栈里生成,并在代码段结束时弹出消失。
若是这样子,你会怎么生成代码? 目前的编译器恐怕都无法做得到
beepbug 回复于:2007-05-20 17:11:18
为实体分配空间,有静态、动态之分。后者又分栈分配和堆分配。
所谓静态,是指在程序加载形成进程所做的分配。进程结束时消亡。
所谓动态,是在进程运行中做的分配。
看静态分配,只要看源码就行了。你要看汇编码也行。用GDB看机器码都一样。就是只看程序,就可了解。
动态分配就不能只看程序。程序里有的,在进程里不一定产生。栈分配是这样,堆分配也一样。否则叫啥动态分配?
mik 回复于:2007-05-20 17:15:49
引用:原帖由 beepbug 于 2007-5-20 17:11 发表
为实体分配空间,有静态、动态之分。后者又分栈分配和堆分配。
所谓静态,是指在程序加载形成进程所做的分配。进程结束时消亡。
所谓动态,是在进程运行中做的分配。
看静态分配,只要看源码就行了。你要 ...
:em06: true 时生成动态分配变量 ? 在堆中用,编译器生成用 malloc() 的代码 ? 那在栈中怎么动态生成呢
beepbug 回复于:2007-05-21 11:29:57
引用:原帖由 mik 于 2007-5-20 17:15 发表
:em06: true 时生成动态分配变量 ? 在堆中用,编译器生成用 malloc() 的代码 ? 那在栈中怎么动态生成呢
我说的已经很清楚了。再贴一次:
为实体分配空间,有静态、动态之分。后者又分栈分配和堆分配。
所谓静态,是指在程序加载形成进程所做的分配。进程结束时消亡。
所谓动态,是在进程运行中做的分配。
看静态分配,只要看源码就行了。你要看汇编码也行。用GDB看机器码都一样。就是只看程序,就可了解。
动态分配就不能只看程序。程序里有的,在进程里不一定产生。栈分配是这样,堆分配也一样。否则叫啥动态分配?
这个i在栈里。
动态分配≠堆分配,它包含堆分配,还有栈分配。
再说一遍,请先看清楼主的帖意:
像下面这样的代码如果这个if分枝没有被执行那么这个变量i是否存在? 我指的是物理上而不是逻辑上, 也就是这个i是不是动态分配的?
楼主是问“这个i是不是动态分配的? ”
不管对不对,我是在回答这个问题。我不知道你们两位版主是在回答什么问题?
对错,大家可以讨论。但不要跑题。
flw 回复于:2007-05-21 11:38:58
引用:原帖由 JohnBull 于 2007-5-20 10:05 发表
这要看在这个标准中,变量定义是否被看作普通语句了。
照你的说法,汇编源码中必然有根据条件对ESP进行调整的代码了,而实际上呢?
你只要自己写一段测试代码,去不同平台,用不同语言标准编译成汇编代码,看看就知道了。
请帖出测试结果再进一步发言。
你这个话前后有点儿矛盾。
看标准没错,我想这个帖子的标准答案也只能从标准中得来。
至于“去不同平台,用不同语言标准编译成汇编代码”,我觉得即使看到了结果,如果找不到标准中必须要这么做的条文的话,那答案也是不完整的。
白天晒太阳 回复于:2007-05-21 14:08:35
引用:原帖由 koolcoy 于 2007-5-18 15:05 发表
像下面这样的代码如果这个if分枝没有被执行那么这个变量i是否存在? 我指的是物理上而不是逻辑上, 也就是这个i是不是动态分配的? (C语言, 不是C++)
if (xxx) {
int i;
}
:em23::em23:如果没有被执行当然不会在物理上分配资源了,它的生存周期在那对花括号“{}”中
如果不被执行当然也不会运行那个花括号所表示的语句(即花括号具有的属性和方法),当然不会分配资源鸟
LZ大概对物理及其逻辑之间的抽象关系木有深入的分析研究:em05::em05::em05:
思一克 回复于:2007-05-21 16:08:32
to beepbug,
if (xxx) {
int i;
}
i 无论XXX是真是假,无论进入不进入if{},都已经是分配的了. 是在进入if所在的FUNCTION开始分配的. 和进入if无关.
LZ问的动态的意思是是否随着if(xxx)的进入而按需要分的(如果不进入就不分), 从这意义上不是动态的. 当然相对与if所在函数是动态的.但LZ问的不是哪个意思.
编译WHY这么做?为了效率,同时不违反什么
什么叫"不能看程序"?
许多问题倒是"不能看书"得到答案.
Alyd 回复于:2007-05-21 16:37:30
这个i 的生存期都在这对{}内;无论进入分支,i都生成了的(在函数的栈内有 i );
用脑袋想想,难道在函数运行的时候,再在栈里面分配一个内存空间给i么? 这个编译的时候都已经确定了要给i一个空间;
思克斑竹说的对。。。。
wuliang_227 回复于:2007-05-21 16:42:13
不访问应该不存在
beepbug 回复于:2007-05-21 20:49:41
引用:原帖由 思一克 于 2007-5-21 16:08 发表
i 无论XXX是真是假,无论进入不进入if{},都已经是分配的了. 是在进入if所在的FUNCTION开始分配的. 和进入if无关.
LZ问的动态的意思是是否随着if(xxx)的进入而按需要分的(如果不进入就不分), 从这意义上不是动态的. 当然相对与if所在函数是动态的.但LZ问的不是哪个意思.
[u]这段看不懂。你自己看得懂嘛?[/u]
编译WHY这么做?为了效率,同时不违反什么
什么叫"不能看程序"?
许多问题倒是"不能看书"得到答案.
我没叫你别看程序。只是说,先要弄清问题。
我劝你还是要看书。看看进程与存储分配方面的书。
beepbug 回复于:2007-05-21 20:55:04
局部变量生成在栈里。当进入它所在的代码块时,生成(实质上是做压栈操作),离开该代码块时,消失(弹出操作。实际上该变量还在,只是逻辑上我们认为它不存在了,不可访问了。)。再次进入该代码块时,再次生成。为什么把栈分配归入动态分配,就是这个原因。
mik 回复于:2007-05-21 20:58:45
引用:原帖由 beepbug 于 2007-5-21 20:49 发表
我没叫你别看程序。只是说,先要弄清问题。
我劝你还是要看书。看看进程与存储分配方面的书。
汗~~
这位仁兄貌似很牛,不知是否果真这么牛。但相信和克版还是有一段差距的。
另:请拿点实际出来支持你的论点。贴出[color=Blue]编译出来的代码[/color]或者[color=Blue]自已试着实现 if(){} 为 true 时和 false 时生成变量的代码[/color]
思一克 回复于:2007-05-21 20:59:11
to 楼上,
我看了LZ的问题几秒后就弄清问题了,也说出正确答案了.
是你没有弄清, 才说了那么多海阔天空来.
引用:原帖由 beepbug 于 2007-5-21 20:49 发表
我没叫你别看程序。只是说,先要弄清问题。
我劝你还是要看书。看看进程与存储分配方面的书。
思一克 回复于:2007-05-21 21:10:26
TO beepbug,
你根本没有弄明白,根据书本的理论在加符合逻辑的想象就得出了不正确的结论.
许多编译根本没有根据"代码块"动态地" "压栈" "弹出". GCC+就没有.
还有,这东西你争论什么? 这不是不存在事实的理论性的东西还可以争论和有争论的余地.
这个是一个十分简单的事实. 不具有争论的前提. 在G++上看一下C产生的汇编代码就有结论了.
可能有例外. 比如在什么其他编译上.
引用:原帖由 beepbug 于 2007-5-21 20:55 发表
局部变量生成在栈里。当进入它所在的代码块时,生成(实质上是做压栈操作),离开该代码块时,消失(弹出操作。实际上该变量还在,只是逻辑上我们认为它不存在了,不可访问了。)。再次进入该代码块时,再次生成。 ...
mik 回复于:2007-05-21 21:36:41
c99 支持的动态数组,这是唯一能够被利用去支持 beepbug 论点的唯一一种实现方式吧。
不过,利用条件的真假来计算生成变量空间,比计算数组大小难度大得非常多。恐怕没一个编译器做得到。至少目前没有吧。
即使能这样做到。但也不能算是所谓的动态生成,还是有形的
思一克 回复于:2007-05-21 21:49:03
自己看吧.
[CODE]
#include <stdio.h>
main(int argc, char **argv)
{
int i;
i = 123;
if(argc) {
int a[128];
a[1] = 456;
}
}
.file "tt.c"
.text
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
subl $536, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $123, -12(%ebp)
cmpl $0, 8(%ebp)
je .L2
//这里就是if块内. 512个字节空间早在外面就留好了的. 块内无动态申请归还
movl $456, -532(%ebp)
.L2:
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
[/CODE]
antigloss 回复于:2007-05-22 00:53:06
引用:原帖由 思一克 于 2007-5-21 21:49 发表
subl $536, %esp
andl $-16, %esp
[color=Red] movl $0, %eax
subl %eax, %esp[/color]
movl $123, -12(%ebp)
一直搞不清楚这两行是做什么用的,麻烦知道的人讲解一下。
思一克 回复于:2007-05-22 08:39:18
是GCC计算调整(优化?)STACK的什么方法。没有深入研究。
如果程序是这样(多分100个整数),那么调整成为更复杂的:
[CODE]
main(int argc, char **argv)
{
int i;
int k[100];
i = 123;
if(argc) {
int a[128];
a[1] = 456;
}
}
--------
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
[/CODE]
net_robber 回复于:2007-05-22 11:50:47
这几天没有钻研技术,没看到这么经典的讨论,呵呵
我支持看汇编代码的说法
理论上怎么讲都没用
理论上我们现在应该每个人都是世界首富了
但实际上,这里都是穷人
呵呵
我们说了都不算
机器说了算
choc 回复于:2007-05-22 12:29:52
标准好象是定义变量应该放在所有语句前面吧,反正我在编译内核的时候想放一些标记进去,结果叫我定义在前面去。
比如for (int i = 0; i < 100; i++)这种好象都不允许
MMMIX 回复于:2007-05-22 12:35:22
引用:原帖由 choc 于 2007-5-22 12:29 发表
比如for (int i = 0; i < 100; i++)这种好象都不允许
这种用法 C99 和 C++ 都是允许的。
choc 回复于:2007-05-22 12:45:38
那GCC-4.0是用的什么标准?
beepbug 回复于:2007-05-22 20:34:34
两位版主注意自身形象,注意自己的身份。
思一克 回复于:2007-05-22 21:28:10
其中有我吧?
本来就注意了的.
引用:原帖由 beepbug 于 2007-5-22 20:34 发表
两位版主注意自身形象,注意自己的身份。
fisdailar 回复于:2007-05-22 21:54:25
不是动态分配的,它在栈里面
zeseler 回复于:2007-05-23 18:13:59
杂跑这么远呀!汇编都来拉呀!
priboy 回复于:2007-05-23 18:52:00
引用:原帖由 beepbug 于 2007-5-22 20:34 发表
两位版主注意自身形象,注意自己的身份。
晕。
whyglinux 回复于:2007-05-23 20:38:21
引用:原帖由 koolcoy 于 2007-5-18 15:05 发表
像下面这样的代码如果这个if分枝没有被执行那么这个变量i是否存在? 我指的是物理上而不是逻辑上, 也就是这个i是不是动态分配的? (C语言, 不是C++)
if (xxx) {
int i;
}
首先,i 是一个自动变量,所以它的存储空间是自动分配的,而不是动态分配的(当然,也不是静态分配的)。
其次,你问的这个问题涉及到具体实现,而对同一段程序可能有多种实现方式,所以很难给出一个准确的答案。另外,“在物理上存在”的具体含义也值得商榷。
自动变量一般对应着进程的栈空间。在具体实现中多以函数为单位使用栈,也就是说:在编译的时候已经根据自动变量的数量和类型确定出了函数需要的栈空间,并确定了变量在此空间中的相对地址(或相对偏移)。这样,当程序执行到函数的时候,函数使用的栈空间已经被保留,相应地,自动变量的地址被确定。从这个意义上来说,似乎我们可以说这个变量在执行到函数的时候物理上已经存在了。
自动变量对应的栈空间也可能被同一函数中定义在不同块中的变量使用,所以物理上存在不意味着逻辑上也存在。
如果程序以块为单位组织栈,是不是我们就可以说只有进入变量作用域之后在物理上才存在?
自动变量 i 也有可能被编译器设置为寄存器变量。寄存器是始终存在的,那么这个自动变量什么时候在物理上存在?是进入作用域的时候、进入函数的时候、程序开始执行的时候、甚至程序尚未执行就已经存在了?
思一克 回复于:2007-05-23 21:02:45
LS非常好和全面的回答
fedora_core_7 回复于:2007-05-23 22:08:34
引用:原帖由 思一克 于 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 , 其它的编译器可能有不同的处理...
flw2 回复于:2007-05-23 22:33:04
我觉得whyglinux和版主说的都比较有道理。
当然,如果非要“绝对正确”,看标准吧,而且现在存在的若干种计算机体系结构n,并不能假设n ! =无穷大。
标准没有规定的,一切皆有可能,但是如果这样讨论就是多余的了
不看汇编看c代码是不能确定的。 看汇编,看看i对应什么东西就知道了。
思一克 回复于:2007-05-24 08:38:24
那这个恰当吧。
if(argc) 和if(0) 不同。后者可以被编译优化掉。前者还没有。
一样的。i[128]是在函数(不是块)进入就分好的。
[CODE]
main(int argc, char **argv)
{
int i = atol(argv[1]);
int k = 123;
if(i) {
int i[128];
i[1] = 456;
}
}
main(int argc, char **argv)
{
int i = atol(argv[1]);
.file "tabc.c"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $536, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
subl $12, %esp
movl 12(%ebp), %eax
addl $4, %eax
pushl (%eax)
call atol
addl $16, %esp
movl %eax, -12(%ebp)
movl $123, -16(%ebp)
cmpl $0, -12(%ebp)
je .L2
movl $456, -532(%ebp)
.L2:
leave
ret
.size main, .-main
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)"
[/CODE]
引用:原帖由 fedora_core_7 于 2007-5-23 22:08 发表
这个例子是不恰当的,因为 argc 永远不会是0,所以 if(argc) 相当于 if(TRUE), 故int a[128]一定会执行到,因此编译器为它分配了空间。如果你把 if(argc) 改成 if(0) 再看看汇编,编译器是不会为它分配空 ...
shmilylxx 回复于:2007-05-24 09:16:56
这个问题我觉得意义不大
1,C89不支持这种定义方式
2,即使支持这种方式,具体编译器的实现也有出入,
虽然是仅仅作用空间才有效,但是在栈中分配的时间,或许在进入该函数的时候就分配了。这个标准C没有定义的~
思一克 回复于:2007-05-24 09:22:00
本来意义不大。但是该帖子也有学习编译代码产生机理的作用。可以帮助深入了解C
C标准没有定义。所以现有的答案就是上面的。有反例,可以举出。
引用:原帖由 shmilylxx 于 2007-5-24 09:16 发表
这个问题我觉得意义不大
1,C89不支持这种定义方式
2,即使支持这种方式,具体编译器的实现也有出入,
虽然是仅仅作用空间才有效,但是在栈中分配的时间,或许在进入该函数的时候就分配了。这个标准C没有定义的~
beepbug 回复于:2007-05-24 15:38:30
1)同为动态分配的堆分配和栈分配有很大的区别。在程序启动时,还没有堆分配,虚的实的,都没有。但是,加载器为栈空间做了一次性的虚空间分配,大小是从用户空间最高端到链接器确定的栈下限。在程序运行期间,这个没有变化。但是,只向系统申请了一页物理内存。因为至少要存放环境变量等。如果以后这一页用完了,就再申请一页。弹出多了,可能会回收一页实存。
前面一位说得对,有的东西物理上存在,逻辑上却当它没有了。压入一个元素,再把它弹出,物理上它还在,可逻辑上当它没有了。
2)我还是认为,对这个问题来说,看C码,看汇编码,看机器码,是一回事。本来在C码有的东西,编译后,在汇编码里当然也存在。否则是被编译器贪污了。
但是,程序里出现的东西,进程里并一定出现。光看汇编,不能得出结论。
但是,也不绝对排除未用到的东西出现在进程里。前面说的并行计算也算一个例子。
思一克 回复于:2007-05-24 15:56:41
“光看汇编,不能得出结论。”
就事论事,单就这个问题,光看LINUX I386 GCC汇编,不能得出其上的结论吗?
antigloss 回复于:2007-05-24 19:12:18
引用:原帖由 fedora_core_7 于 2007-5-23 22:08 发表
这个例子是不恰当的,因为[color=Red] argc 永远不会是0[/color],所以 if(argc) 相当于 if(TRUE), 故int a[128]一定会执行到,因此编译器为它分配了空间。如果你把 if(argc) 改成 if(0) 再看看汇编,编译器是不会为它分配空 ...
记得以前看过一篇文章,说 argc 在某种情况(忘了)下会是0。
Alligator27 回复于:2007-05-24 20:55:50
引用:原帖由 beepbug 于 2007-5-24 15:38 发表
1)同为动态分配的堆分配和栈分配有很大的区别。在程序启动时,还没有堆分配,虚的实的,都没有。但是,加载器为栈空间做了一次性的虚空间分配,大小是从用户空间最高端到链接器确定的栈下限。在程序运行期间,这 ...
第一点不太对, 加载器不能为栈空间(main thread)做一次性的虚空间分配. 而是程序运行期间逐步延伸的.
Alligator27 回复于:2007-05-24 21:25:05
以前面思一克的例子
main(int argc, char **argv)
{
int i = atol(argv[1]);
int k = 123;
if(i) {
int i[128];
i[1] = 456;
}
}
程序执行到 if(i) 的时候, 进程的内存(virtual or physical)没有因 int i[128] 而变化, 虽然compiler 预备了它的空间.
subl $536, %esp
也就是说如果main()调用另一函数, 其栈必在 int i[128]之后, 不管 if(i) 是否成立.
compiler 设定%ebp, %esp的值只是改变进程的context, 进程的内存image并未变动.
如果 if(i) 为真, 内存写操作 i[1] = 456;
movl $456, -532(%ebp)
如果内存地址-532(%ebp)未被读写过, 而且落在新页上, 进程的内存, 准确说其栈空间被OS VMM自动延伸一页. 只有这个时候才能看到进程的memory footprint增加.
fedora_core_7 回复于:2007-05-24 21:25:36
引用:原帖由 思一克 于 2007-5-24 08:38 发表
那这个恰当吧。
if(argc) 和if(0) 不同。后者可以被编译优化掉。前者还没有。
一样的。i[128]是在函数(不是块)进入就分好的。
[CODE]
main(int argc, char **argv)
{
int i = atol(argv[1]);
...
你可能只看了我的第一段话,没注意到第二段,第二段就是讨论的if中是变量的情况,当不开优化时,编译器确实会分配,但如果开了优化选项(-O2),if中的内容会自动被优化掉,因为那里面的处理不会对程序的结果产生任何影响。当然,你要既想开优化选项,又一定要执行if里内容的话,也是可以的,只不过得用 volatile int i[128] 来定义了。有兴趣可以试一下:D
思一克 回复于:2007-05-24 22:24:57
这里讨论的问题没有涉及物理页的. 而是指程序用的虚拟内存.
如果非要涉及物理页,那么你可以认为分配块所在FUNCTION被CALL之前已经调用过许多其他的东西, 这才是最一般的情况.
将块放在main()中仅仅为了举例方便而已.
引用:原帖由 Alligator27 于 2007-5-24 21:25 发表
以前面思一克的例子
main(int argc, char **argv)
{
int i = atol(argv[1]);
int k = 123;
if(i) {
int i[128];
i[1] = 456;
}
}
程序执行到 if(i) 的时候, 进程的内存(virtual o ...
Alligator27 回复于:2007-05-24 22:38:03
引用:原帖由 思一克 于 2007-5-24 22:24 发表
这里讨论的问题没有涉及物理页的. 而是指程序用的虚拟内存.
如果非要涉及物理页,那么你可以认为分配块所在FUNCTION被CALL之前已经调用过许多其他的东西, 这才是最一般的情况.
将块放在main()中仅仅为了举例方 ...
我说的是虚拟页.
vatdog 回复于:2007-05-25 14:04:20
这个问题不好说。
可能要牵涉到C++和Java的Run Time 的概念了。
因为传统的C语言不支持这样的动态数据定义。
在后来的C++和Java里才出现的概念。
根据我在大学里Java的知识,这类动态的数据定义在编译器上有2种具体实现:
1。 默认为全局加载数据,这个方法的好处是不必考虑太多的动态细节。不过需要在名字空间做一定规范,防止冲突。
2。动态式的堆空间申请,这个在Java中有很好的例子: classLoader,就是显示的动态调用。当然编译器也对关键字做了些隐式调用,譬如楼主说的int XXX的定义。Java解析器运行的时候就是通过运行时来判断的,如果执行到该步骤,则隐式的调用new功能在堆里创建一个int对象(即在Run Time时判断)。当然我们可以象C一样自己手动采用alloc方式来产生一个变量,如果编译器足够强大(如C++)我们则可以简单写成int XXX,那些细节由编译搞定就OK。
a1406 回复于:2007-06-02 12:37:45
我没去找过这个问题的相关标准的定义(偷懒)。
也没有去看反汇编的代码,因为编译器的实现有时候只是为了方便。
不过我觉得。
这个变量是一定在栈里面的。他所用的栈地址在括号之前可以被别人用,也就是说,进入函数的时候,留出的栈大小可以不包括这个变量的,当然他要他这个包括在内也没问题,这样方便。而括号之后这个地址也可以被别人用。
换言之,可以把这个括号中的部分看成一个没有参数出入栈,返回地址出入栈的简化的函数调用(自己YY的)。
呵呵
|