为什么不在循环外部和内部声明具有相同名称的变量会产生错误?
{ int i; for(i=0;i<5;i++) { int i=10; printf("%d",i); } }
我有两个问题
- 为什么我没有重新申报错误?
- 为什么输出将是
10
5次而不是10
1次?
这一切都与标识符的范围有关。 标识符只是在C中赋予实体(对象,函数,typedef名称等)的名称,根据C11 6.2.1 /1
:
相同的标识符可以表示程序中不同点的不同实体。
实体的范围在该部分的/2
中描述:
对于标识符指定的每个不同实体,标识符仅在称为其范围的程序文本的区域内可见(即,可以使用)。
/4
涵盖您的具体案例:
如果标识符指定同一名称空间中的两个不同实体,则范围可能会重叠。 如果是这样,一个实体(内部范围)的范围将严格地在另一个实体(外部范围)的范围之前结束。
换句话说,类似于:
{ int i = 42; printf ("%d ", i); { int i = 17; printf ("%d ", i); } printf ("%d\n", i); }
是完全有效的,将打印42 17 42
。 那是因为内部块中的标识符i
在其自己的范围内,其结束于第一个右括号。
在您的特定情况下,您可以将其视为:
{ int i; \ for(i=0;i<5;i++) > outer i scope { / int i=10; \ printf("%d",i); > inner i scope } / }
内部int i=10
有效隐藏了外部i
用于for
循环体的持续时间。 这就是为什么它打印很多10
秒而不是0..4
。
内部的范围在for
循环体的闭合支撑处完成,因此,当检查for
循环的延续条件时,它再次看到外部i
。 这就是为什么它循环五次而不是一次。
在你的代码中
-
int i;
在外部块范围内。 -
int i=10;
在for
循环的内部块范围内
如果我们想象一下,我们可以提出像’
{ //---------------------------| int i; | for(i=0;i<5;i++) | { | int i=10; //-------| inner scope |> Outer scope printf("%d",i); //-------| | } | } //----------------------------|
这里的情况是, 内部 i
将遮蔽外部i
。 这两个被认为是单独的变量( 基于它们的范围 )。
换句话说,在块 (内部范围)内定义和存在的i
将具有更多的偏好(在外部范围内的变量上)。 因此,内部i
值将被打印。
OTOH,循环计数器变量i
仍然在外部范围。 它的价值不会因为街区内的分配而改变。 所以,正如所问的那样,它正好循环了5次。
相关:从C11
标准,章节§6.2.1,第4段,
.. [..] ..如果标识符指定同一名称空间中的两个不同实体,则范围可能会重叠。 如果是这样,一个实体( 内部范围 )的范围将严格地在另一个实体( 外部范围 )的范围之前结束。 在内部范围内,标识符指定在内部范围内声明的实体; 在外部作用域中声明的实体在内部作用域内是隐藏的 (并且不可见)。
那么,回答你的问题,
为什么我没有重新申报错误?
因为两个i
被视为单独的变量 ,尽管被命名为相同。
为什么输出将是
10
5次而不是10
1次?
因为,用作计数器的外部i
不会从循环内部改变,只有循环增量条件才会改变该值。
你没有重新声明我,因为i(’int i = 10’)的第二个声明是在循环中。 这意味着在您的示例中,变量将被销毁并为循环的每次迭代重新创建。
在任何复合语句中创建的变量范围仅限于复合语句本身。
Ps:如果你想通过改变i的值来停止循环
{ int i; for(i=0;i<5;i++) { i=10; printf("%d",i); } }
如果你很好地问你的编译器( gcc -Wshadow
)它会警告你
echo -e '#include \nvoid f(void) { int i; for (i = 0; i < 5; i++) { int i = 10; printf("%d", i); } }' | gcc -Wshadow -xc -c -
:在函数'f'中: :2:53:警告:声明“我”阴影前一个本地[-Wshadow] :2:20:注意:阴影声明就在这里