前言
(1)之前肯哥在交流群中抛出了一个这样的问题。我当时的想法是全局变量肯定要赋初值啊,这不是C语言刚学习时候的基础知识吗?有什么可以提供讨论的?
(2)但是,后来在我写完RAM明明断电会丢失数据,为什么初始化的全局变量存储在RAM?详细分析程序的存储这一篇博客之后,有了另外的想法。
(3)
<1>hello all 又到了每天的open话题时刻,今天来聊点技术细节:你在C语言的工程中,全局变量,你会随手赋初值吗?你知道赋初值和不赋初值的区别是什么吗?更进一步,什么时候应该赋初值,什么时候可以无所谓赋不赋初值呢?
<2>这个话题,我暂时不发表意见,还请感兴趣的小伙伴来讨论讨论。
<3>我只分享一个曾经出现在我的开发团队中的小故事:曾经有一次组内做code review的时候,一位经验老道的以开发单片机程序为主的攻城狮,跟我们争论得很厉害,他的主张是全局变量不要赋初值。
<4>朋友们,你认为呢?
(4)注意:阅读本文之前,需要对RAM明明断电会丢失数据,为什么初始化的全局变量存储在RAM?详细分析程序的存储的知识有一个了解。否则看不懂。
本文讨论的实际内容是什么
(1)首先,我们需要知道全局变量的存储位置是在哪里。我们都知道,数据存储有代码段,常量区,静态数据区,栈,堆这五个部分。而全局变量是存储在静态数据区的。
(2)静态数据去又分为BSS段和数据段。BSS段负责存储没有被初始化的全局变量和静态变量。数据段存储未初始化或显示初始化为0的全局变量和静态变量。
(3)因此我们可以知道,本文要讨论的其实就是,静态数据区的BSS段和数据段有什么区别。
BSS段和数据段的存储区别
(1)如果你去搜索,会发现有些人说:在程序编译的时候,不会给.bss段中的数据分配空间,只是记录数据所需空间的大小。在程序执行的时候,才会给.bss段中的数据分配内存。通过这种方式,可以节省一部分内存空间,进一步缩减可执行程序的大小。
(2)可能有些人会疑惑了,记录空间大小不要占用空间吗?我们需要知道,对于计算机系统而言,访问一个空间,其实就是知道他的地址,并且接下来在这个起始地址访问几个字节。那么,我们只需要在程序中知道起始地址和访问字节数就可以了。这样就成功的将BSS段的数据存储下来了。
(3)但是数据段不一样,你不但要在代码中记录他的起始地址和访问的字节数,还需要保存他的初始值。这个值也就是RW-Data。
(4)在单片机上电的瞬间,存储在ROM的RW-Data数据(也就是静态数据区的数据段)会被复制到指定RAM位置。但是注意,这里是复制,也就是说,RW-Data数据在RAM和ROM中都有一份数据!
(5)上电之后,程序运行,代码中知道了ZI-Data(也就是静态数据区的BSS段)的起始位置和访问空间。因此,这个就可以理解为,为ZI-Data开辟了一段空间。
全局变量不初始化的好处
(1)根据上面我们知道了不初始化的全局变量存储在BSS段。BSS段不需要ROM再额外分配空间存储初始化的值,这样就可以有效的节约ROM空间。
(2)但是,这个时候有人可能就要问了,不初始化的变量,他的初始值是未知的啊,那会导致程序不具备唯一性质!而且和我们刚学C语言的相违背啊。
<1>首先,我们需要知道一点,我们初学C语言的时候,所运行的环境是什么。而绝大多数嵌入式工程师所使用的开发环境又是什么。
<2>我们初学C语言的时候,都是直接在PC机上运行的,所以说,你节约那几B的数据,对于有几百GB内存的PC机来说,毫无意义。
<3>而大多数嵌入式工程师,所使用的开发环境,可能就几十KB甚至几KB,能省则省。
<4>这个时候有人就要说了,那不初始化,那变量是未知的啊。所以说,这个就要看情况而论了。
(3)以我的理解,如果是一些不太重要,他对整个系统影响不是特别大,而且后续代码还会对他赋值的变量。可以不进行初始化。而有一些,需要进行自增自减的变量,对系统具有一定的决定性因素的变量。还是初始化好一点。