Delphi中for循环后的循环变量是什么?

9
在Delphi中,考虑以下内容:
var
  i: integer;

begin

  for i := 0 to N do
  begin
    { Code }
  end;

有人可能认为在for循环之后,i = N,但是Delphi编译器能保证这一点吗?在一个Delphi if循环中,在循环内部可以假设循环变量等于它的最后一个值吗?
更新
尝试了几个简单的循环后,我怀疑循环结束后i实际上等于循环内i的最后一个值加一...但是这样可靠吗?

你确定在 for 循环后 N 仍在作用域内吗?我建议先检查一下,因为我怀疑它可能已经不在作用域内了。 - LBushkin
@LBushkin:这取决于N是如何声明的。但在上面的代码示例中,我只使用N作为“占位符”,代表循环变量的最后一个值可能是什么。 - Andreas Rejbrand
@LBushkin,你可以毫无疑问地确信在循环之后 N 会在作用域内,因为显然在循环之前它就已经在作用域内了(否则代码就不会编译通过)。在Delphi中,作用域不会在函数运行过程中改变;它从函数的开始开始,直到结束。 - Rob Kennedy
但你能信赖这个吗?- 不行 - Gabriel
6个回答

26
不,Delphi 不保证任何值。在循环外,变量是未定义的 - 如果我没记错,语言指南明确说明了这一点 - 这意味着较新的编译器实现可以自由更改变量在循环外可能具有的任何值,这取决于实际实现。

5
这是正确的。变量在循环完成后被明确记录为未定义。如果您需要在循环后使用已定义的变量,请使用while或repeat。 - Nick Hodges
3
根据循环变量在循环中的使用方式,编译器甚至可以完全消除它,并仅使用指针迭代数组元素。 - Allen Bauer
7
除非您使用'break'语句终止循环,否则"..."是未定义的。在这种情况下,变量被定义为循环计数器在执行'break'之前所具有的值(即'break'执行前的最后一个值)。 - gabr
3
Gabr是正确的。如果你使用break离开循环,控制变量的值将保持有效。同样,如果你使用exit离开循环,控制变量的值也会保持有效。文档中已经有这样的说明。虽然没有正式记录,但通常认为,通过raisegoto离开循环也会保留变量的值。 - Rob Kennedy
1
如果循环内部没有使用该变量,编译器可能会生成从N到0的计数代码,即使源代码要求从0到N计数,因为这样稍微更有效率。在这种情况下,我不知道该变量在循环后会有什么值。 - dummzeuch
显示剩余5条评论

7
编译器实际上会在循环后使用循环变量时发出警告,因此您应该将其视为未定义。

6

如果您需要在循环后使用循环索引,则我建议使用while循环,因为这样更清晰:

i := 0;
while i <= N
begin
    { Code }
    i := i + 1;
end;

循环终止后,你会知道i将会是N + 1(或更大,如果N可能小于零)。


是的,那是一个非常好的方法。毕竟,每个for循环都可以用这种方式写成while循环,但没有任何“编译器魔法”。 - Andreas Rejbrand
2
你可以使用Inc(i)代替i := i + 1,但是如果我没记错的话,编译器会将它们视为相同的。 - Gerry Coll

2

甚至有文档记录了在循环之外,for循环的循环变量是未定义的。

实际上:从变量中获取的内容取决于编译器设置和代码复杂性。我曾经看到代码的更改将编译器推入不同的优化路径,从而修改了这个未定义变量的值。

--jeroen


1

正如许多人所说,循环后变量I应该是未定义的。在实际使用中,它将被定义为在“break”之前最后一个值,或者如果循环运行到末尾,则为N + 1。但是不能依赖这种行为,因为明确指定它不起作用。

此外,有时候甚至不会分配I。我遇到过这种行为,主要是在开启优化时。

对于像这样的代码

I := 1234;
For I := 0 to List.Count - 1 do
begin
  //some code
end;
//Here, I = 1234 if List.Count = 0

所以...如果你想知道循环后I的值,最好在退出循环之前将其赋值给另一个变量。

1

永远不要在循环结束后依赖于for变量的值。

检查你的编译器输出。Delphi编译器会对此发出警告。相信你的编译器。

  1. 永远不要使用{$Warnings off}隐藏编译器的提示和警告!
  2. 学会将信息视为警告,将警告视为错误!
  3. 优化你的代码,直到你没有任何提示和警告(不违反规则1)。

这可能有点太“严格”了。例如,在许多情况下,“函数的返回值可能未定义”的警告是不相关的。 - Andreas Rejbrand
编译器说某些东西可能未定义,而实际上不可能的情况非常罕见。我见过的唯一情况是涉及两个条件语句分配结果,并且其中一个必须运行。即使我知道它们是无害的,我认为值得写一些额外的代码来抑制所有警告。 - Loren Pechtel
1
如жһњењЁе‡Ңж•°е†…йѓЁдҢүз”ЁraiseжЉ›е‡ғеә‚еёёпәЊж€–иЂ…ж··еђ€дҢүз”ЁExit(ReturnValue)ж–№жі•е’ЊиЂЃеәЏзљ„result :=ж–№жі•пәЊе€™з»ЏеёёдәљеЏ‘з”џиү™з§Қ情况。 - Andreas Rejbrand
例如,在许多情况下,警告“函数...的返回值可能未定义”是无关紧要的 - 学会初始化该变量。不过,这些情况并不多。 - Gabriel
1
"我认为值得花费一点额外的代码来抑制所有警告,即使我知道它们是无害的。" - 有一个干净的编译器输出不是很好吗? :) - Gabriel
@Altar:是的,这本身就是一个收益。它还使得日志中更严重的问题更容易被发现。 - Andreas Rejbrand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接