请问for循环内部为什么不可以修改循环变量的值?(200)

  • 主题发起人 deardragon_2002
  • 开始时间
D

deardragon_2002

Unregistered / Unconfirmed
GUEST, unregistred user!
翻译后的机器码,循环上限和循环变量是被保存在两个单独的寄存器中的(这个跟C++、VB相比,让人有点难以接受)。保存循环上限的寄存器,只在循环前被循环变量初始化了一次,后面循环中,对循环变量的修改,都不会影响到循环上限的变化。哪位大侠能解释下这样的设计理念,为什么要这么设计,在循环内部不可以修改循环上限啊?
 
D

deardragon_2002

Unregistered / Unconfirmed
GUEST, unregistred user!
。。。。。。。。。
 
W

wql

Unregistered / Unconfirmed
GUEST, unregistred user!
哎,谁说不可以修改 Var GlobeI : Word;procedure DemoFor;vari:word
beginGlobeI:=5;for i:=1 to GlobeI dobeginif i:=3 then globeI:=100;end
end;只是不能修改过程和函数内部的循环变量,因为可能是堆栈式分配的,例如:i---->[bp+100]
 
D

dafuwenn

Unregistered / Unconfirmed
GUEST, unregistred user!
我要分!~
 
D

Diroc

Unregistered / Unconfirmed
GUEST, unregistred user!
新手,说错了别笑话撒...[8)]个人感觉的原因:1、可能因为跟0的比较速度相对较快,所以只要是循环,编辑出来的汇编都是类似于:DEC EAX
JNZ @...
RET;//eax这里就是指循环变量了,而且正如楼主所说,是循环上限,如果写成for I := 0 to 3,那么eax就是4,写成for I := 3 to 5,那么,eax就是3了。循环一次eax就自减1,减完判断是否是等于0,不是0继续执行,是0就退出循环。2、基于以上原因,如果你改了循环变量,改成小于0的,那么这个循环就永远停不了,因为越减离0越远。PS:你说的循环变量保存在一个寄存器里,是什么意思?没看明白,循环变量是不分配内存的吧...
 
G

gencheng

Unregistered / Unconfirmed
GUEST, unregistred user!
你用While不行吗?
 
D

daxian

Unregistered / Unconfirmed
GUEST, unregistred user!
Diroc 说的靠谱,与0比较速度快另外 一般这个 会放到特殊的寄存器,这个寄存器的加一减一速度更快甚至如果没有在循环内部使用,会优化成减一比较
 
S

Supermay

Unregistered / Unconfirmed
GUEST, unregistred user!
请问for循环内部为什么不可以修改循环变量的值?这是Pascal编译优化的结果
 
V

vvyang

Unregistered / Unconfirmed
GUEST, unregistred user!
To 楼主:1、200 分有点可惜,我来作终结者吧...2、“循环上限和循环变量是被保存在两个单独的寄存器中的”,首先,您描述的问题本身就是错误的,因为 Delphi 根本就不存在您所说的这个问题...3、举个简单的例子,for i := 2 to 15 do,以下是 Delphi 编译后的汇编码:mov eax, $0e //把循环次数 14(15 - 2 + 1) 存入 eax 寄存器dec eax //把 eax 寄存器内容减 1,如果 eax 为 0 会将 zf 标志寄存器置 1jnz -$03 //判断 zf 标志寄存器是否为 0,为 0 跳转继续循环,否则退出上面的例子中,循环上限是 15,循环变量是 i,如果我没眼花的话,自始至终 Delphi 只使用了一个累加器 eax(zf 标志寄存器不算),何来“循环上限和循环变量是被保存在两个单独的寄存器中的”?4、再举另外一种情况,“上限”是变量的情况:j := 15;for i := 2 to j do上面两条被 Delphi 编译后,应该是这个样子:mov eax, $0f //把 j 的值存入 eax 寄存器sub eax, $02 //把 eax 和 下限 2 相减,差存入 eax,负数的话同时置 sf <> OFjl $04 //判断 sf 是否 OF,not OF 的话(上限小于下限)结束,否则执行下一条指令inc eax //把 eax 中的差值加 1(其实就是循环次数)dec eax //这句才是循环的开始jnz -$03 //跟前面的例子一样,不罗嗦了上面也只用了 eax 一个寄存器。5、所以,楼主所说“循环上限和循环变量是被保存在两个单独的寄存器中”是错误的;上面例子中 eax 保存了循环上限 j 的数值,整个循环只对 CPU 的 eax 寄存器进行加减操作,而变量 j 在内存中好好呆着,当然不会被修改。“后面循环中,对循环变量的修改,都不会影响到循环上限的变化”,循环上限(CPU)和循环变量(内存)压根就是两个世界的东西,你非要它们相互影响干什么?6、“哪位大侠能解释下这样的设计理念,为什么要这么设计,在循环内部不可以修改循环上限啊”,这么设计是必然的,否则 Delphi 就是挂羊头买狗肉了:C 语言的循环一般会出现“j++”之类的玩意,这句话什么意思,就是直接对内存中的变量进行加法操作,j(上限)当然会变了,相当于 Delphi 中i := 2;while i <= 15 do Inc(i);而 Delphi 的循环一般是“for i := 2 to 15 do”之类的,里面哪句话表示要把 i 加 1 或减 1 了?你拿 Delphi 的 for 循环(真正意义上的无条件循环)和 VC 中的 for 循环(相当于 while,属于条件循环)比较,能比较出个啥?编译优化之后,两者在汇编层次上是一样的...另外,循环内部可以修改“循环上限变量”,但不能修改“循环上限”,这个不多说了...
 
V

vvyang

Unregistered / Unconfirmed
GUEST, unregistred user!
To daxian、Diroc:1、这个跟“与0比较速度快”似乎没虾米关系...2、加减操作会导致 zf、sf 标志寄存器变化,jne、jl、jg 是靠判断标志寄存器状态跳转的,而不是靠“与 0 比较”...3、32 位 CPU 一共就十几个寄存器,都挺“特殊”的,另外 4 个通用寄存器都能进行加减操作...4、其实“加一”或“减一”并不是优化的结果,而是书写习惯问题;如果事先向 eax 中置入循环次数的负值,用“加一”操作可以达到同样的效果...
 
D

Diroc

Unregistered / Unconfirmed
GUEST, unregistred user!
我说的与0比较快,其实想表达的是,直接判断zf标志位,比再做一次循环变量是否超界的判断来得快……[:D]
 
顶部