我遇到了这段C代码:
main(){
static int i=0;
i++;
if(i<=5){
int i = 3;
printf(" %d",i);
main();
}
}
1。首先,由于变量i
有多个定义,我希望此代码能够提供编译错误。但是,它编译并成功运行并提供了此输出。
3 3 3 3 3
2。观察输出, 3 正好打印5次,这意味着循环从 0到5 计算,这意味着对于 if condition ,使用i
的第一个定义(静态)。
3 但是,正在打印的值为 3 ,这是i
的第二个定义。
因此变量标签i
指的是内存中的两个不同实例。一个用作循环计数,用于增量,另一个用于打印值。
我能以某种方式解释这一点的唯一方法是:
int i = 3
(第二个定义)。 i
的实例是在调用函数时创建的,并在下一次递归调用时被终止。 (因为静态范围)。 printf
使用此实例,因为它是最新的定义(?)
当输入新的递归级别时,i++
正在完成。由于没有其他方法可以解析此i
,因此它使用i
的静态“实例”,它在代码中仍然是“活动的”,因为它被定义为静态。
然而,我无法确切地说明这是如何工作的......有人能解释一下这里发生了什么,在代码和内存中?
编译器如何在这里完成变量绑定?
答案 0 :(得分:4)
内部范围胜出。
示例:
int i = 1;
void foo() {
int i = 2; // hides the global i
{
int i = 3; // hides local i
}
}
此行为是设计使然。您可以做的是对变量范围使用不同的命名约定:
如果在同一函数中隐藏变量(例如函数参数和常规局部变量),某些编译器将发出警告。所以你是编译器的最大警告级别。
答案 1 :(得分:1)
if语句的{}
创建新的块范围,当您在该范围内声明i
时,您隐藏外部范围中的i
。新范围直到{
才开始,因此 if语句指的是外部范围中的i
。
C99标准部分草案中涵盖了隐藏6.2.1
标识符范围段 4 表示(强调我的):< / p>
[...]如果标识符指定同名的两个不同实体 空间,范围可能重叠。如果是这样,一个实体(内部范围)的范围将是a 另一个实体范围的严格子集(外部范围)。在内部范围内, identifier指定在内部作用域中声明的实体; 在外部范围内声明的实体在内部范围内隐藏(并且不可见)。
答案 2 :(得分:1)
当存在多个该变量的变量时,编译器将始终使用变量的最本地版本。
在循环之外,第一个i
是唯一存在的i
,因此它是被检查的那个。然后创建一个新的i
,值为3.此时,只要你谈论i
,它就会假设你的意思是第二个,因为那是更本地化的。当您退出循环时,第二个i
将超出范围并被删除,因此如果您再次开始讨论{{1}},它将是第一个。