为什么 C 编译器不在 for 循环体内给出重新声明错误?
Why doesn't the C compiler give a redeclaration error inside a for loop body?
在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++ 中,编译器会给出 "redeclaration of 'long int i'" 错误。
那么,为什么 C 编译器不给出重声明错误呢?是编译器错误吗?
首先,循环内部没有重新声明。在循环体内。 i
每次进入循环都定义,作用域只到循环体。
一旦循环完成迭代,变量就不再存在了。 (第一个引用)
也就是说,您所看到的是 阴影 的结果。 (第二个引用)
引用 C11
,
If the declarator or type specifier that
declares the identifier appears inside a block or within the list of parameter declarations in
a function definition, the identifier has block scope, which terminates at the end of the
associated block. [...]
并且,
[...] If an identifier designates two different entities in the same name
space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end
strictly before the scope of the other entity (the outer scope). Within the inner scope, the
identifier designates the entity declared in the inner scope; the entity declared in the outer
scope is hidden (and not visible) within the inner scope.
C++和C在这里有所区别。根据C11 (n1570) §6.8.5 ¶5,强调我的:
An iteration statement is a block whose scope is a strict subset of
the scope of its enclosing block. The loop body is also a block whose
scope is a strict subset of the scope of the iteration statement.
这转化为 for 循环:
{
declaration
while ( expression) {
statement
expression ;
}
}
您在 statement
部分中放入的任何内容都可以隐藏声明中引入的任何内容。现在,C++(17, n4659) 在 [stmt.for]/1 处明确表示了类似的内容。但它还继续添加:
except that names declared in the init-statement are in the same
declarative region as those declared in the condition,
所以这里的第二个i
确实是在尝试重新声明。上面可能听起来很混乱(条件中声明的名称!?),但是这里的 "condition" 是这样定义的 ([stmt.stmt]/1):
condition:
expression
attribute-specifier-seq decl-specifier-seq declarator brace-or-equal-initializer
它允许像这样的 while 循环 (C++ only):
while (T t = x) statement
和you may not re-declare t
在while循环的语句里面。
或者,我得出的全部结论总结在[stmt.iter]/3(谢谢@T.C):
If a name introduced in an init-statement or for-range-declaration is
redeclared in the outermost block of the substatement, the program is
ill-formed.
不是重新声明。 (不是字面意思,有些人可能仍然这么叫)
仔细看这个...
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
具有更多本地范围。
是bug吗?
没有
目的是什么?
如果不允许,维护大型项目可能会非常困难,因为您会经常 运行 陷入命名冲突。
虽然一般来说,为不同范围内的不同变量赋予相同的名称被认为是非常糟糕的做法,您应该尽可能避免这样做。
为什么没有警告信息?
使用gcc file_name.c -Wshadow
编译。
编辑: 您还可以通过在 for 循环中重新声明来本地锁定最初声明的变量。
在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++ 中,编译器会给出 "redeclaration of 'long int i'" 错误。
那么,为什么 C 编译器不给出重声明错误呢?是编译器错误吗?
首先,循环内部没有重新声明。在循环体内。 i
每次进入循环都定义,作用域只到循环体。
一旦循环完成迭代,变量就不再存在了。 (第一个引用)
也就是说,您所看到的是 阴影 的结果。 (第二个引用)
引用 C11
,
If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block. [...]
并且,
[...] If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
C++和C在这里有所区别。根据C11 (n1570) §6.8.5 ¶5,强调我的:
An iteration statement is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.
这转化为 for 循环:
{
declaration
while ( expression) {
statement
expression ;
}
}
您在 statement
部分中放入的任何内容都可以隐藏声明中引入的任何内容。现在,C++(17, n4659) 在 [stmt.for]/1 处明确表示了类似的内容。但它还继续添加:
except that names declared in the init-statement are in the same declarative region as those declared in the condition,
所以这里的第二个i
确实是在尝试重新声明。上面可能听起来很混乱(条件中声明的名称!?),但是这里的 "condition" 是这样定义的 ([stmt.stmt]/1):
condition:
expression
attribute-specifier-seq decl-specifier-seq declarator brace-or-equal-initializer
它允许像这样的 while 循环 (C++ only):
while (T t = x) statement
和you may not re-declare t
在while循环的语句里面。
或者,我得出的全部结论总结在[stmt.iter]/3(谢谢@T.C):
If a name introduced in an init-statement or for-range-declaration is redeclared in the outermost block of the substatement, the program is ill-formed.
不是重新声明。 (不是字面意思,有些人可能仍然这么叫)
仔细看这个...
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
具有更多本地范围。
是bug吗?
没有
目的是什么?
如果不允许,维护大型项目可能会非常困难,因为您会经常 运行 陷入命名冲突。
虽然一般来说,为不同范围内的不同变量赋予相同的名称被认为是非常糟糕的做法,您应该尽可能避免这样做。
为什么没有警告信息?
使用gcc file_name.c -Wshadow
编译。
编辑: 您还可以通过在 for 循环中重新声明来本地锁定最初声明的变量。