在for循环中声明一个int变量为什么是不良实践?

3

在我的大学C++课程中,我习惯于并且被教导在for循环中声明一个int变量,像这样:

for(int i = 0; i < 5; i++)
{
    // code
 }

但是现在我正在修读一门机电一体化课程,我们要用c和Arduino编写代码,老师告诉我这样做是不好的实践,并建议采用如下方式:

int i = 0;
for(i; i < 5; i++)
    //code

为什么会有一个比另一个更受青睐?

15
这并不是一种糟糕的做法。只是在过去,“定义变量”只能限制在函数的开头进行。除非你被迫使用一些旧的 C 修订版,否则这种限制现在已经过时了。 - Eugene Sh.
11
第二种方法在早期版本的C语言中是必需的,现在它大多只是为了遗留支持和出于习惯而存在。现代实践通常鼓励将对象的范围限制在最小范围内,并将变量定义靠近其首次使用的地方。这两种做法都建议使用 for(int i; i<5; ++i) 这种形式。 - François Andrieux
5
除非第一个无法编译,否则请优先选择第一个;如果第一个无法编译,请选择第二个。 - john
3
这个问题的回答是否对您有所帮助?[在循环中声明变量,是良好的编程习惯还是不良习惯?] - Shivendra Agarwal
7
未经解释就将合法的风格宣布为“不良实践”是糟糕的教学。向您的导师询问为什么这是不良实践,并以开放心态倾听。他们可能有一个正当的观点,或者他们可能被困在1987年,或者您可能误解了他们最初所说的内容。无论发生什么,您都会学到一些东西。 - Caleb
显示剩余4条评论
4个回答

6

机电一体化课程

我会进行一个合理的猜测。

你所使用的编译器可能很笨,会将此代码编译为:

for(int i = 0; i < 5; i++) {
    //code
}
for(int i = 0; i < 5; i++) {
    //code
}

使用两个独立的堆栈变量。现代编译器比这好,但嵌入式系统有旧的愚蠢编译器,而老师们记得问题已经解决很久了。鉴于这是Arduino,如果您拥有最新的编译器,那么它现在就是完全错误的。

我记得使用一个编译器,这段代码会出现"i已经被声明"的错误提示,但我偏离了主题。


听起来像是OP正在使用Arduino,它在底层使用的是C++编译器。因此,这个限制根本就没有意义。 - Eugene Sh.
@EugeneSh.:我遇到这个问题的编译器是C++编译器。 - Joshua
哦,我明白你的答案是关于什么的了。一开始我误解了它。 - Eugene Sh.
“一个编译器如果在这段代码中出现 i 已经被声明的错误会崩溃” - 实际上,微软的 Visual C++ 曾经有过这个 bug!荒谬。因此,必须在 for 循环中添加额外的大括号。 - Bungo

5
为什么一个优于另一个?
如果您例如提前跳出循环,则可能想要知道i的最后一个值,当然只有在它在循环外部声明时才能访问。 因此,在这种情况下,这是唯一的选项(除非您为此使用单独的变量,但这会增加不必要的复杂性)。
但通常情况下,当两者都是有效选项时,将所有变量声明在最小的可能范围内可能略微更有效,并且更易阅读——虽然后者可能是主观的,因此这主要是品味问题。 前者在一般情况下并非“不良做法”。

1
说实话,这并不是坏的做法,唯一的区别是在第二种情况下迭代器将在循环完成后仍然可访问。

6
那是一个相当幼稚的经验法则,很容易出现逆效果。乍一看听起来不错,但简短的代码并不一定是更好的代码。通常情况下,编写略长但更清晰的代码会更好。 - François Andrieux
2
@user15244951:不会的。无论哪种情况下,内存都会在函数返回时被释放。编译器不会为非可变长度数组发出堆栈帧大小更改器。 - Joshua
@Joshua,那么我使用局部作用域来尽早释放内存的所有工作都被浪费了? - user15244951
1
如果你的编译器是2010年之后的版本,那么是的。如果是旧版本,我们都只能猜测。(不适用于管理堆分配的对象。) - Joshua
@user4581301 但我添加 {} 的时间的整个目的是手动释放堆栈内存 :( - user15244951
显示剩余5条评论

1
C89/ANSI标准要求所有变量在作用域块的顶部声明。这是因为旧的C编译器是单遍编译器,意味着它们在程序上进行一次并且唯一的解析、类型检查和机器代码发射。由于机器代码在解析时被发射,因此需要在遇到给定作用域块时知道要保留多少堆栈空间,这就是为什么旧标准规定变量必须在顶部声明的原因。
新的C编译器是多遍编译器,意味着它们对程序进行多次遍历。因此,在初始遍历中不再需要知道要保留多少堆栈空间。
嵌入式系统通常使用遵循旧的C89/ANSI标准的C编译器。您的老师可能鼓励您在顶部声明变量,以便您永远不必考虑它。随着课程的进展,他们可能会给出更详细的解释,就像我所做的那样。

如果编译器可以处理if块内的变量声明,它会向后传播堆栈帧大小。 - Joshua

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