你可以在哪里,不能在C中声明新的variables?

我听到(可能来自一位老师)应该在程序/函数之上声明所有的variables,并且在声明中声明新的variables可能会导致问题。

但是当时我正在读K&R,而且我遇到了这样一句话:“variables的声明(包括初始化)可以在左括号之后,引入任何复合语句,而不仅仅是开始函数的语句”。 他举了一个例子:

if (n > 0){ int i; for (i=0;i<n;i++) ... } 

我对这个概念起了一点作用,即使对于数组也是如此。 例如:

 int main(){ int x = 0 ; while (x<10){ if (x>5){ int y[x]; y[0] = 10; printf("%d %d\n",y[0],y[4]); } x++; } } 

那么到底什么时候我不允许声明variables呢? 例如,如果我的variables声明不正确的后面大括号? 像这样:

 int main(){ int x = 10; x++; printf("%d\n",x); int z = 6; printf("%d\n",z); } 

这可能会造成麻烦取决于程序/机器?

我也经常听到把variables放在函数的顶部是做事的最好方法,但我强烈反对。 我倾向于将variables限制在可能的最小范围内,这样他们就不太可能被误用,所以我在计划的每一行中都填充了更less的东西。

虽然C的所有版本都允许使用词法块作用域,但您可以在其中声明variables取决于您所定位的C标准版本:

C99或C ++

现代C编译器如gcc和clang支持C99和C11标准,它们允许您在声明可以去的任何地方声明一个variables。 variables的作用域从声明点开始到块结束(下一个右括号)。

 if( x < 10 ){ printf("%d", 17); // z is not in scope in this line int z = 42; printf("%d", z); // z is in scope in this line } 

你也可以在循环初始化器中声明variables。 该variables将只存在于循环中。

 for(int i=0; i<10; i++){ printf("%d", i); } 

ANSI C(C90)

如果你的目标是早期的ANSI C标准,这恰好是微软MSVC编译器所支持的最新ANSI C标准,那么你仅限于在大括号1之后立即声明variables。

这并不意味着你必须在你的函数顶部声明所有的variables。 在C语言中,你可以在语句可以去的任何位置放置一个大括号分隔的块(不仅仅是像iffor类的东西),你可以用它来引入新的variables作用域。 以下是以前C99示例的ANSI C版本:

 if( x < 10 ){ printf("%d", 17); // z is not in scope in this line { int z = 42; printf("%d", z); // z is in scope in this line } } {int i; for(i=0; i<10; i++){ printf("%d", i); }} 

1请注意,如果您使用的是gcc,您需要传递--pedantic标志来实际执行C90标准,并抱怨variables声明在错误的地方。 如果只使用-std=c90它会使gcc接受C90的超集,这也允许更灵活的C99variables声明。

missingno涵盖了ANSI C允许的内容,但是他没有解释为什么你的老师告诉你在函数的顶部声明你的variables。 在奇怪的地方声明variables会使你的代码难以阅读,并且会导致错误。

以下面的代码为例。

 #include <stdio.h> int main() { int i, j; i = 20; j = 30; printf("(1) i: %d, j: %d\n", i, j); { int i; i = 88; j = 99; printf("(2) i: %d, j: %d\n", i, j); } printf("(3) i: %d, j: %d\n", i, j); return 0; } 

正如你所看到的,我宣布了两次。 那么,更确切地说,我已经声明了两个variables,都是名字i 。 你可能会认为这会导致一个错误,但它不会,因为这两个ivariables是在不同的范围。 当你看这个函数的输出时,你可以看得更清楚。

 (1) i: 20, j: 30 (2) i: 88, j: 99 (3) i: 20, j: 99 

首先,我们分别给予ij 20和30。 那么,在花括号内,我们分配了88和99.那么,为什么j保持其价值,但i又回到了20? 这是因为两个不同的ivariables。

在内层的大括号中,值为20的variables是隐藏的,不可访问,但是由于我们没有声明新的j ,我们仍然使用外部范围的j 。 当我们离开花括号的内层时,持有价值88的i消失了,我们再次访问价值为20的i

有时这种行为是好事,其他时候也许不行,但是应该清楚的是,如果你不分青红皂白地使用C的这个特性,那么你真的可能会让你的代码混乱,难以理解。

如果你的编译器允许的话,你可以在任何你想要的地方申报。 事实上,当你声明你使用的variables而不是函数的顶部时,代码更具可读性(恕我直言),因为它更容易发现错误,例如忘记初始化variables或意外隐藏variables。

一篇文章显示了以下代码:

 //C99 printf("%d", 17); int z=42; printf("%d", z); //ANSI C printf("%d", 17); { int z=42; printf("%d", z); } 

我想这意味着这些是相同的。 他们不是。 如果int z位于此代码片段的底部,则会导致对第一个z定义的重定义错误,而不是第二个定义错误。

但是,多行:

 //C99 for(int i=0; i<10; i++){} 

确实有效 显示了这个C99规则的微妙之处。

就我个人而言,我热烈回避这个C99的function。

如这些例子所示,缩小variables范围的论点是错误的。 在新的规则下,在扫描完整个块之前,您无法安全地声明一个variables,而以前您只需要了解每个块的头部正在发生什么。

按照K&R的C语言编程 –

在C语言中,所有variables必须在使用之前声明,通常在任何可执行语句之前的函数的开头。

在这里,你可以看到通常它不是必须的