查看原文
其他

【嵌入式】bug粉碎机之C语言变量作用域的坑

bug菌 最后一个bug 2022-10-14

1、聊一聊

    今天分享的歌曲名称是"年少轻狂"的意思,一听开头就是一个好歌!当然经典的还是这句"my youth is yours".


    文章跟大家分享下C语言变量作用域的一个总结,这块对于编程老手而言,再简单不过了, 不过这中间还是会有一些有意思的问题。



3、C语言变量作用域

    

    这个话题主要是受交流群里面小哥的调试分享,感觉这块虽然简单,不过还蛮有意思的,所以总结分享给大家。


    

    C语言变量总的来说主要分为 : 全局变量;静态全局;局部变量;静态局部。


    然而奇妙的一点是这些变量可以使用相同的变量名,编译器却可以正确识别和编译的主要原因是他们有各自不同的作用域,从而让编译器能够正确区分。


作用域


  • 全局变量 :  一旦定义和声明了即可供程序访问;

  • 静态全局:一旦定义和声明了即在文件中访问;(静态全局如何声明?)

  • 静态局部:仅在{}代码块之间进行访问;

  • 局部变量:仅在{}代码块之间进行访问;


    这里理论规则bug菌就讲这么多,把一些细节通过后面的代码说明一下。


2、作用域细节


同名变量谁更强

1///////File : main.c
2#include <stdio.h>
3#include <stdlib.h>
4#include "Fuc.h"
5
6int bug = 111;    //全局变量 
7
8/********************************
9 *Fuction: 测试变量作用域
10 *Author :(公众号:最后一个bug) 
11 ******************************/
 
12int main(int argc, char *argv[])
13{
14   printf("bug1 = %d\n",bug);
15   Fuction();
16   return 0;
17}
18
19
20///////File : Fuc.c
21#include <stdio.h>
22#include <stdlib.h>
23#include "Fuc.h" 
24
25//static int bug = 222; 
26
27extern int bug; 
28/********************************
29 *Fuction: 测试变量作用域 Fuction
30 *Author :(公众号:最后一个bug) 
31 ******************************/
 
32void Fuction(void)
33{
34    printf("bug2 = %d\n",bug);
35    if(bug > 0)
36    {
37       int bug = 333;
38       printf("bug3 = %d\n",bug);
39       if(bug > 0)
40       {
41         int bug = 444;
42         printf("bug4 = %d\n",bug);
43       }
44
45    }
46}
47
48///////File : Fuc.h
49#ifndef __FUC_H__
50#define __FUC_H__
51
52extern void Fuction(void);
53
54#endif  
输出结果:

分析一下:

     上面bug菌在DevC++5.7上面运行的结果,虽然全部用的bug变量,大部分小伙伴应该都能够得到正确的结果,其中bug2当然使用的是全局变量了。


     然而我们把文件Fuc.c中间的static bug = 222;放开注释,可以得到如下结果:



     其输出结果表明编译器会优先选择静态全局变量来进行处理而非外部全局。

易错点

     

    对于编程习惯不是很好的小伙伴,在很久以前留了一个静态的全局bug变量在文件的开头或者其他地方,然而程序中又正在使用一个同名的全局变量试图在外部修改,然后在本文件中使用,此时就会发现根本没法通过外部修改影响到内部状态,因为你修改的外部全局变量根本就不是本文件中的同名变量。


   当然如果你能够直接在线仿真还是能够比较容易找到该问题,毕竟停下来以后鼠标点到两个名字会有不同的值;所以编程习惯比较好的小伙伴应该大部分不会遇到该问题。


    所以也不建议大家在程序中定义相同的变量名称,并且变量定义后者声明尽量比较集中。


作用域总结

通过上面的程序,我们可以一句话总结变量作用域 : 谁管辖的范围小,从定义/声明开始处谁最大。



静态变量声明易错


    下面的代码仅仅只是在前面的Fuc.c文件做了一下简单的修改,用于说明静态变量的声明:


1#include <stdio.h>
2#include <stdlib.h>
3#include "Fuc.h" 
4
5
6static int bug;  //声明 
7
8
9/********************************
10 *Fuction: 测试变量作用域 Fuction
11 *Author :(公众号:最后一个bug) 
12 ******************************/
 
13void Fuction(void)
14{
15    printf("bug2 = %d\n",bug);
16    if(bug > 0)
17    {
18       int bug = 333;
19       printf("bug3 = %d\n",bug);
20       if(bug > 0)
21       {
22         int bug = 444;
23         printf("bug4 = %d\n",bug);
24       }
25
26    }
27}
28
29
30
31static int bug = 222//定义 
32
33/********************************
34 *Fuction: 测试变量作用域 Fuction
35 *Author :(公众号:最后一个bug) 
36 ******************************/
 
37void Fuction2(void)
38{
39    printf("bug5 = %d\n",bug);
40    if(bug > 0)
41    {
42       int bug = 333;
43       printf("bug6 = %d\n",bug);
44       if(bug > 0)
45       {
46         int bug = 444;
47         printf("bug7 = %d\n",bug);
48       }
49
50    }
51}
分析一下:

     上面分别是静态变量的声明和定义,你可能会发现这里的静态变量的声明和未初始化的静态全局变量定义是一样的。


    如果你习惯给静态变量初始化编译器会报重复定义,如果你不习惯初始化,如果时间久了,代码不规范, 还一直认为该变量初始化默认是0,其实后面的定义初始化就引入了bug隐患。


    同时大家还可以尝试在函数内部extern,或者在其他编译器里面来定义并使用同名变量,你会发现更多有意思的地方,同时也是大家需要注意的地方,最终规避掉这些问题还是需要有良好的编程习惯!


3、最后小结

     该部分就这点内容吧,比较简单、也不多,或许以后会是查找bug的一个方向,毕竟在公司里面一般一套代码不是一个人开发,各种bug都是有可能遇到的。


    好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。

推荐好文  点击蓝色字体即可跳转

【收藏】【看门狗软件设计】"喂狗"真那么简单吗?

【嵌入式】bug粉碎机之volatile的那些坑

【MCU】用stm32的UID给固件加密(重点在加密)

【硬核C进阶】如何实现 万能 "两数交换" 宏 ?

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存