最近自己在写单片机程序,遇到一个非常有意思的地方就是作用域,学过c语言的都知道作用域的意思是作用范围,例如全局变量的作用域为整个项目,项目中所有的源文件都可以对该全局变量进行读写访问,static修饰的静态全局变量,只能在所在同一个源文件内部的函数进行读写访问,如果是在某一个函数内部定义的临时栈变量或者static修饰的临时栈变量,它的作用域为所在的一对大括号。
这些可能是大家都熟知的只是,今天主要是分析for循环中定义的临时栈变量和for循坏外面定义的临时栈变量如果同名是否编译器报错呢?
我们来看两个这样的例子:
cpp
{
uint8_t i = 12;
... // 其他代码
for (uint i=0; i<2; i++)
{
... // 其他代码
}
i++; // 其他代码
}
例子2:
cpp
{
for(uint8_t i = 0; i<12; i++)
{
... // 一些代码
}
... // 一些代码
uint8_t i = 12;
i++; // 一些代码
}
这两个例子的共同特点就是都定义了一个for循环,for循环内部定义了一个临时栈变量i;不同点在于在这个for循环上面或者下面代码中又定义了一共同名的临时栈变量i。
现在的问题是:编译器是否会报错呢?
答案:否定的,编译器不会报错。首先以上两种情况,函数运行是每一个例子都会申请2个独立的栈变量,也就是2个同名的临时栈变量实际上是两个独立的栈变量,占用不同的内存空间。for循环内部定义的临时栈变量i的作用域为它所在的一对大括号{}(这是我以前理解错误的,我以前错误任务for循环内部定义的临时栈变量也为外面一对大括号的作用域,也就是例子3中的认识,这种想法是错误的),for循环运行解说,这个临时栈变量会自动释放。
例子3:
cpp
{
uint8_t i;
... // 其他代码
for (i=0; i<2; i++)
{
... // 其他代码
}
i++; // 其他代码
}
因此案例2比较好理解就是for循环结束,已经将所在uint8_t i释放掉了,后面的代码才再次去申请一次,两个变量不会同时存在,同一时间只存在一个临时栈变量i,因此比较容易理解。
比较难理解的是案例1,for循环外面定义了一个临时栈变量i,在函数运行时会申请一个临时栈变量,它的作用域为for循环外面一对大括号所在整个作用域,后面for循环内部有定义一个临时栈变量名字也是i,函数运行到这个for循环会再次申请另外一个独立的临时栈变量名字也是i,占用另外一个不同的栈变量内存空间,我理解2个临时栈变量虽然看起来名字相同,但是因为占用不用占空间,所以编译器应该会用在内部进行区分,总之现在存在两个临时栈变量,而不是同一个临时栈变量。for循环内部的代码使用的是它自己第二次申请的栈变量,在for循环结束后,会自动释放这个临时栈变量,因此后面的如果还是这个变量,使用的是第一次申请的变量i,因此编译器不会报错。
理解的关键:
(1)变量的作用域为其所在的一对大括号{}所在区域;
(2)for循环内部定义临时栈变量,它的作用域为for循环自身的一对大括号{}所在区域。for循环运行完自动释放(释放过程也是编译器编译生成的某个机器码完成的)。
(3)例子1、2中的同名栈变量,是两个独立的栈变量,占用不同栈空间。