在C语言中,如果我们这样写:
for(int i = 0; i < 7; i++)
{
// for loop Body
}
变量i
的范围在for循环体内。可以。
但是,如果我这样写:
for(int i = 0; i < 7; i++)
{
long int i = 1; // Redeclaration of i
}
在这里,变量i
在循环体内再次声明,但它成功地编译并在C中运行。
但是,在C ++中,编译器给出了“重新声明'long int i'” 错误。
那么,为什么C编译器没有给出重新声明错误?是编译器错误吗?
答案 0 :(得分:13)
C ++和C在这里有所区别。根据{{3}},强调我的观点:
迭代语句是一个块,其范围是的严格子集 其封闭块的范围。 循环主体也是一个块, scope是迭代语句范围的严格子集。。
将其翻译为for循环:
{
declaration
while ( expression) {
statement
expression ;
}
}
您在statement
部分中放置的任何内容都可以隐藏声明中引入的任何内容。现在,C ++(17,n4659)在C11 (n1570) §6.8.5 ¶5处明确声明了类似的内容。但它还会继续添加:
除非init语句中声明的名称相同 声明区域为条件中声明的区域,
因此,这里第二个i
确实是在尝试重新声明。上面的内容听起来令人困惑(在条件中声明了名称!?),但是此处的“条件”是这样定义的([stmt.for]/1):
condition:
expression
attribute-specifier-seq decl-specifier-seq declarator brace-or-equal-initializer
正是这样允许while循环这样的([stmt.stmt]/1):
while (T t = x) statement
和C++ only在while循环的语句中。
或者,我得出的全部结论总结在you may not re-declare t
中(感谢@ T.C。):
如果在初始声明或for-range-声明中引入的名称是 在子语句的最外层块中重新声明,该程序是 格式不正确。
答案 1 :(得分:2)
首先,循环内没有重新声明。在循环体内。 i
是在每次进入循环时定义的,作用域仅直到循环体为止。
一旦循环完成迭代,该变量将不再存在。 (首引)
话虽如此,您看到的是 shadowing 的结果。 (第二个报价)
引用C11
,
如果声明符或类型说明符 声明标识符出现在一个块内或其中的参数声明列表中 函数定义,标识符具有块作用域,该作用域终止于 关联的块。 [...]
和
[...]如果标识符以相同的名称指定两个不同的实体 空间,范围可能会重叠。如果是这样,一个实体的范围(内部范围)将结束 严格在其他实体的范围(外部范围)之前。在内部范围内, 标识符指定在内部范围内声明的实体;在外部声明的实体 范围在内部范围内是隐藏的(不可见)。
答案 2 :(得分:0)
这不是重新声明。 (从字面上看,尽管有些人还是会称呼它)
请仔细阅读...
for(int i = 0; i < 7; i++)
{
printf("i = %d\n", i);
int i = 5;
printf("new i = %d\n", i);
}
以上代码的输出:-
i = 0
new i = 5
i = 1
new i = 5
i = 2
new i = 5
i = 3
new i = 5
i = 4
new i = 5
i = 5
new i = 5
i = 6
new i = 5
很明显,有两个不同的i
较新的i
具有更广泛的本地范围。
这是一个错误吗?
否
目的是什么?
如果不允许这样做,则维护大型项目可能会非常困难,因为您会经常遇到命名冲突。
尽管通常来说,对不同范围内的不同变量使用相同的名称被认为是非常差的做法,但应尽可能避免这样做。
为什么没有警告消息?
使用gcc file_name.c -Wshadow
进行编译。
编辑: 您还可以通过在for循环中重新声明原始声明的变量来本地锁定原始声明的变量。