• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

单片机入门:C语言讲解(一)

好久没来电源网发帖,学习电子技术的过程中积累了一点心得体会,总想直抒胸臆,可身边没几个同行,只好跑到电源网写点酸文,贻笑与大方之家。

既然是技术心得类的帖子,肯定存在理解不透彻的地方,肯定有自己没有关注到的知识点,还望大家海涵,及时斧正,谢谢。

先在此挖个坑,慢慢填吧,可能会虎头蛇尾,但肯定会不定期更新。

全部回复(95)
正序查看
倒序查看
ltjltjltj
LV.1
2
2021-04-09 20:31
期待
0
回复
LV.1
3
2021-04-10 00:09
留名
0
回复
2021-04-10 17:17

    C语言参考书籍为《C primer Plus》第五版,《C语言深度解剖》,同时也融入了自己的一点感悟与心得。

    说心里话,C语言的书籍以及视频教程看了很多,但还是觉得不够透彻,理解不够深入。希望热心的网友能够及时补充纠正。

    操作系统为ubuntu18.04_x86_64,编译器采用的是gcc version 7.5.0 (ubuntu18.04_x86_64),后期的开发板验证采用的是金沙滩的51单片机开发板,编译器为keil uversion 4(windows_xp_x86_32),单片机采用的是STC89C52单片机。

1
回复
2021-04-10 17:28

    我自己的初期架构是写一点51单片机相关的帖子,主要内容为基于51单片机的C语言,汇编语言,单片机硬件结构,寄存器等。

    目前也没有给自己定一个太过具体的任务计划,主要目的有两个,第一是通过发帖把单片机涉及的相关知识点梳理清楚,第二结合自己的学习心得帮帮那些想学单片机又苦于没有找到适合的学习方法的朋友,希望我走过的学习弯路能给大家一些启发。

1
回复
2021-04-10 17:41

    这篇帖子主要针对想靠单片机这门手艺吃饭的入门级工程师。搞了几十年开关电源,射频电子同时又自认为单片机这玩意太简单的大牛级工程师就别看了。特别希望得到搞了多年单片机开发,乐于帮助后进且恰巧看到帖子的工程师的指导,谢谢。

    另外,不管什么类型的杠精都别看了,我真的不愿意和杠精抬扛,第一累,第二浪费时间。

1
回复
兰波
LV.8
7
2021-04-10 22:14
哈哈,你也玩软的了?C语言我会一些。
0
回复
2021-04-12 20:42

    说心里话,很早就想写一点有关C语言的学习文章,但是怎么写,才能让大家相对愉快地学习,我也想了很久。为此我也翻了很多程序语言书籍,自认为积累了一点学习经验,分享给大家,下面转入正题。

    讲解程序语言,教科书大多从琐碎的语法结构开始,这样的讲解方式直接把多数的学生拒之门外。回想我当年学习C语言的经历,只能说苦不堪言。起初C语言的书籍是我的枕边读物,一般晚上入睡前翻一两页,相当有助于睡眠。

    我们能不能站得更高一点,尝试着采用先整体后局部的方法讲讲C语言呢?换句话说,我们能否先将程序语言的框架搭起来,然后再根据功能需求用各种语法一步一步地完善框架,最终使其成为完整的程序。

    通俗点说,就是先建立骨架,再摸索着往骨架上填充血肉,接着尝试关联各个功能部件,最后大功告成。当然过程肯定不会一帆风顺,必然存在诸多的问题,通过不断地调试,最终问题都会解决,功能也会实现。

   

1
回复
2021-04-12 21:07

    不管何种程序语言,其最终的执行机构肯定是计算机,那程序语言的各种语法规则必须要符合电子计算机的特性,才能保证其执行不出错。据此原则,程序语言的特性必然遵循电子计算机的功能特点,当然这里我并不准备详细分析计算机的硬件功能。

    这就带来一个问题,电子计算机有什么特别之处能有助于我们更好的理解程序呢?这就要绕到另一个问题,电子计算机的运行需要什么?答案是电,没有电,一切的电子设备都得停工。

    那电有什么特点呢,入门类的电工书籍都会用“水”的特性来类比“电”的特性,这里我们也采用此类比法。

1
回复
2021-04-12 21:31

    我家住在长江边上,每当学不下去或者遇到解不开的心结时,我总会到江堤上走一走,转一转,坐一坐,间或举目远眺,心情不同,心境亦不同。此一法非常有助于我个人的心境提升。我的学习心得很多时候是悟出来的,而不是从书本上直接获得的。当然,各人有各人的学习方法,此处不表。

    话说一日,我苦苦思索程序如何运行未果,遂暂时放一放。晚上一个人在江堤上散步,吹着江风,偶尔抬头远望,只有江上渔船零星的灯火以及星星和月亮陪伴着我。我突然灵光乍现,想通了白天苦苦思考的问题。那程序到底是怎么运行的呢?

1
回复
2021-04-12 22:04

    其实程序的运行不就和眼前的滚滚长江水一样吗?流动的长江水必然有其源头以及尽头。长江水在流经不同地貌时,会产生很多的支流,不同的支流又会分化出诸多小支流。支流中有些绕过一段河道后又重新汇入长江,有些则成了一潭死水。

    如果从江水的源头与尽头看,我们可以粗略地认为长江是以直线的运动轨迹川流不息。看看长江的各个支流,我们可以说这是长江的流动分支。再瞧瞧江水绕过的各个湾湾码头,这不是在循环往复吗?

    再看看程序的运行,不也是一样吗。整体上看,程序从上往下依次执行,再执行过程中根据不同条件分化出诸多的节点,有些节点执行一次即可,有些节点需要执行多次,有些节点则直接跳过。

    至此,程序的框架终于清晰了,再结合书本专业知识,我们总算弄通了程序是怎么运行的。

    程序是由顺序结构,分支结构以及循环结构组成的。如果对汇编语言有所了解或者熟悉C语言goto关键字的用法,我们甚至可以说程序语言只有一种结构,那就是跳转结构。再深入一点,若理解了指针的概念,同时懂得一点计算机的组成原理,我们满可以说,程序的本质就是通过合理地规划内存,最大限度发挥计算机内部各功能模块的性能。

0
回复
2021-04-13 09:32

   插个题外话,可能是年龄大了,经历的事情也多,心态慢慢平和了,不知不觉间对古典诗词以及水墨丹青有了些许兴趣。个人觉得古代文人的艺术创作品更多的是写意,此中意境只可意会而不可言传。

    步入中年的我,兴之所至,偶尔会乘汽渡在江上转转,也曾体悟过“落霞与孤鹜齐飞,秋水共长天一色”。生活所迫,日常的琐事过多,中国的大好河山还没机会好好领略,也想参透参透“大漠孤烟直,长河落日圆”的意境。


0
回复
2021-04-13 20:39

    程序的框架分解完成,接下来聊聊程序的存储规则。

    我们通常意义上敲的代码实质是静态的或者说是未运行的程序,这样的程序只能放在ROM中,这里的ROM代指外存储器,比如硬盘,FLASH,EMMC,EEPROM等。

    运行的程序通常称为进程,它通过调用各类寄存器实现某一功能,对于单片机而言,讲进程就有点扯,因为常规单片机速度很慢,一般仅仅用于实现某一特定功能,所以其进程只有一个。真正的进程概念是基于操作系统而言。操作系统中会涉及多个进程的处理,这里就不扩展了。上述对进程的认识只是我个人的粗略描述。

1
回复
2021-04-13 20:55

    进程只能运行于RAM中,单片机上电复位后,固化的微指***令将ROM中的程序加载到RAM中,这时程序就开始运行了。那问题来了,大家有没有想过进程(运行的程序)在内存中是怎么分布的,或者说进程是如何在大片的RAM区中运行的?如果能考虑到这一层次的问题,恭喜你,总算对单片机有了一个相对深入的思考。

    学习C语言以及单片机,很多的工程师的套路都是对照书籍或者例程敲代码,虽然当时按照例程实现了某一功能,但是脱离源码后又不知道从何下手。于是尝试着反复敲例程,重复了很多次后依然没有理解单片机为何物。至此完成了从入门到放弃的过程。

   

        

1
回复
2021-04-13 21:10

    上述放弃学习单片机的工程师离单片机入门仅仅差一小步,那就是思考,准确地说是带着问题去思考。

    学习单片机的心态很重要,我是一个学习单片机失败了很多次的LOSER(我对电子技术没有多少兴趣,坚持至今是因为没有更好的谋生手段罢了,我比常人多了一点耐心,恒心),在此总结归纳一下我认为正确的或者说是恰当的学习单片机的方法及心态。

    第一点是忘,忘掉过往已经掌握的开关电源的系统知识(电源网的大多数受众是电源工程师),对于射频工程师,PLC工程师,上位机软件工程类似。为什么有此一说呢,这是我尝试着学习单片机失败了多次后悟出来的。

    我们一旦有门技术傍身后,总会习惯性地靠这门擅长的手艺谋生,慢慢就形成了依赖,专业术语称作思维舒适区。我们思想中总会有一个误区,认为过往掌握的技能有助于我们学习后面的新知识。不自觉的我们就把以前的思维模式带入到新的知识领域中。这就是最大的问题。

    

0
回复
2021-04-13 21:24
@hello-no1
    上述放弃学习单片机的工程师离单片机入门仅仅差一小步,那就是思考,准确地说是带着问题去思考。    学习单片机的心态很重要,我是一个学习单片机失败了很多次的LOSER(我对电子技术没有多少兴趣,坚持至今是因为没有更好的谋生手段罢了,我比常人多了一点耐心,恒心),在此总结归纳一下我认为正确的或者说是恰当的学习单片机的方法及心态。   第一点是忘,忘掉过往已经掌握的开关电源的系统知识(电源网的大多数受众是电源工程师),对于射频工程师,PLC工程师,上位机软件工程类似。为什么有此一说呢,这是我尝试着学习单片机失败了多次后悟出来的。    我们一旦有门技术傍身后,总会习惯性地靠这门擅长的手艺谋生,慢慢就形成了依赖,专业术语称作思维舒适区。我们思想中总会有一个误区,认为过往掌握的技能有助于我们学习后面的新知识。不自觉的我们就把以前的思维模式带入到新的知识领域中。这就是最大的问题。    

    单片机与开关电源,变频器,射频电子,PLC,上位机软件编程等都是相对独立的技能,不要指望学会了一门手艺后,就能触类旁通其他的相关技能。这是我们开始学习单片机必须要有的思想觉悟。

    不信,你可以问问身边精通单片机,或者PLC,乃至JAVA编程的同事懂不懂开关电源的设计,大概率是不懂的。会抄个反激电源的单片机工程师不算,他那点浅薄的对开关电源的认识不够看。

    能够将开关电源和单片机区分开来学习,你已经成功了一大步。单片机和开关电源是两个不同的领域,虽然熟悉开关电源有助于我们理解单片机中涉及的硬件知识,但这远远不够。

0
回复
2021-04-14 10:59
@hello-no1
   单片机与开关电源,变频器,射频电子,PLC,上位机软件编程等都是相对独立的技能,不要指望学会了一门手艺后,就能触类旁通其他的相关技能。这是我们开始学习单片机必须要有的思想觉悟。    不信,你可以问问身边精通单片机,或者PLC,乃至JAVA编程的同事懂不懂开关电源的设计,大概率是不懂的。会抄个反激电源的单片机工程师不算,他那点浅薄的对开关电源的认识不够看。   能够将开关电源和单片机区分开来学习,你已经成功了一大步。单片机和开关电源是两个不同的领域,虽然熟悉开关电源有助于我们理解单片机中涉及的硬件知识,但这远远不够。
对于电源来说,看行业,比如做数控电源的话,单片机和开关电源都得精通才可以
0
回复
2021-04-16 18:28

    学习单片机需要具有的第二个心态是不急,有耐心。市面上有一些教材号称一个礼拜掌握单片机,这样的教程针对的受众通常是有一定基础的,且资质相对较好的朋友。如果没有一定的知识储备,个人建议还是按部就班的学习。

    知识是逐步缓慢积累的,快速上手的教程最大的副作用可能是营造了一种焦虑的环境,让很多初学者再学过好几遍仍找不着头绪时,开始了自我否定,最终放弃。在此我送给那些一直徘徊在单片机入门阶段的朋友一句话:“坚持就是在快要放弃时再忍耐忍耐。”

    我个人定义单片机技术为一门谋生的手艺,甚至可以说是安身立命的手段,那肯定不太容易掌握,否则满大街的人都会玩,何谈养家糊口一说。

    周围也有很多电子工程师精通单片机技术,那说明这门技术的学习掌握也没有难于上青天。只要努力,理顺思路,储备了足够的知识,找到适合自己的学习方法,肯定可以精通单片机技术。

    

0
回复
2021-04-16 18:49

    学习单片机技术需要具备的第三个心态是恒心,或者说是韧性。想学好单片机必然会遇到各种各样稀奇古怪的问题,这时心态一定要足够坚韧,不能但凡遇到一点困难,一时半会解决不了就想着放弃。

    在某个问题上卡住了,如果以当前的知识储备确实解决不了,那就放一放,继续往前走,千万不能自设囚笼,钻牛角尖把自己困在那里,这一点很重要。我自己属于典型的一根筋,遇到问题总想着立马解决,但身边又缺少能够及时给自己答疑解惑的朋友。在苦思冥想过一番仍不可得时,我就失去了继续往前探索学习的兴趣。等下一次再提起兴趣时,又得从头开始,周而复始,永远困在单片机入门学习的道路上。

    在学习的过程中明知会遇到各种问题而依旧选择努力前行不失为勇者的表现,在遇到超出自己能力范围的问题而选择适时地放一放,可谓是智者的选择。

1
回复
2021-04-16 20:48

    C语言编写的程序经调试编译后生成HEX文件烧写进单片机ROM中,单片机上电复位后,将ROM中的程序引导至RAM中(内存中),单片机便开始正式工作了。我们知道程序都是在内存中运行的,为保证程序高效有序的运行,内存通常被人为的划分为四个区域,这就引出上文提到的内存四区的概念。

    内存区域的划分,我准备梳理两类,一类是C语言内存四区的划分,一类是单片机的内存区域的划分,实质上大同小异。这一章讲讲C语言的内存四区,等写到单片机的内部框架章节时,再列举单片机内存区域的相关知识点。

    

1
回复
lkings
LV.6
21
2021-04-16 21:49
@hello-no1
   C语言编写的程序经调试编译后生成HEX文件烧写进单片机ROM中,单片机上电复位后,将ROM中的程序引导至RAM中(内存中),单片机便开始正式工作了。我们知道程序都是在内存中运行的,为保证程序高效有序的运行,内存通常被人为的划分为四个区域,这就引出上文提到的内存四区的概念。   内存区域的划分,我准备梳理两类,一类是C语言内存四区的划分,一类是单片机的内存区域的划分,实质上大同小异。这一章讲讲C语言的内存四区,等写到单片机的内部框架章节时,再列举单片机内存区域的相关知识点。    
这么好的贴子怎么没人顶,难道都是做硬件的多,楼主加油
2
回复
2021-04-18 13:24

    内存的分配方式实质是由不同的编译器针对不同的单片机架构再配合相应的编程语言决定的。图灵机模型中,内存相当于一段无限长的纸带,指示着机器的下一步动作,周而复始,永不停息。

    但现实世界中,内存是有限的,而机器只要不断电,肯定会不知疲倦地占用内存进行运算处理,经过一定的机器周期,终会耗尽有限的内存。站在哲学的角度,这就是有限与无限的矛盾。

    怎么办呢,是否存在一种方法或者说策略使得有限近似于无限,答案是肯定的。合理的规划内存,同时及时释放回收内存,就能使有限的内存用之不竭。这就是内存区域划分思想的来源。

1
回复
2021-04-18 14:53

    C语言中的内存被分割为四个区域,分别对应着代码区(code),数据区(data),栈区(stack),堆区(heap)。不同区域的功能特性也不尽相同。首先讲讲代码区(code).

    单片机上电复位后,编译生成的HEX代码经由机器内部固化的微指***令加载进内存,实质上代码被引导至内存中的代码区,即code区。该段内存的特性之一是不可以修改,专业术语为只读。其次该区域内容是可共享的(即某段可执行代码能够访问它)。

    C语言代码区可共享的目的是针对频繁调用的只读数据,使用此法可有效提高程序的访问效率。代码区设置为只读的意义在于防止程序运行过程中的意外而修改了某些指***令或数据,导致不可预料的错误发生。

1
回复
2021-04-18 15:22

   51单片机代码区如何配置可共享数据呢?使用51单片机特有的C语言关键字code,即可实现。C51中该类变量常用于存放一些复杂函数的固定值数据,如各类真值表,三角函数值,反三角函数值,对数值,指数值等。

    为什么要这样做呢?很多的8位机,16位机内部并没有浮点运算器,遇到复杂一些的运算基本都不能胜任,而用户仅仅关注最后的结果。我们在程序中预先给出运算结果,当涉及某一功能函数计算时,直接将代码区中对应的运算结果调用显示即可。此种方法既高效,又节省了大量机器资源。这种思想在单片机技术中被称作查表执行。

    51单片机中code关键字修饰的数据,其特性为只读。从单片机内部资源的角度看,此类数据存储至程序空间ROM中(C语言中则为代码区)。这样可以大大节省单片机的RAM使用量,毕竟我们的单片机RAM空间比较小,而程序空间相对大的多。

  


1
回复
2021-04-18 15:54
    数据区,顾名思义用于存放各种特性的数据。该区域存放的数据有全局变量(Global_Variable)、静态变量(Static_Variable)、常量(Constant)。由于数据区存放此三类变量,所以又被称为全局区或静态区。至于全局变量,静态变量以及常量该如何定义,它们之间的差异在后续讲解C语言详细语法时再介绍。

    数据区又可以细分为data区,bss区及常量区。其中data区里主要存放的是已经初始化的全局变量、静态变量。bss区主要存放未初始化的全局变量、静态变量。未初始化的数据在程序执行前会被编译器自动初始化为0或NULL。顾名思义常量区存放的是一些常量,如const关键字修饰的全局变量以及字符串常量等。

    数据区中的数据相较于代码区中的数据,其不仅可读而且可写。可读表明该区域里的数据可被函数调用,可写表明该区域中的数据能够被改变。该区域数据的特点是只要内存不掉电,数据就能一直存活。单片机中的各功能寄存器也有此类似特性。只要配置好寄存器相关数据后,寄存器中的数据就能一直存在,除非掉电。有很多场合的应用需要保证寄存器中的数据不丢失,为防止外界电源断电,单片机系统会接入备用电池。如实时时钟,日历,低功耗模式等。

    不同类型的变量在内存中的存活时间各不相同,这一特性专业术语称作变量的生命周期。其次可读数据变量在内存中能被哪些函数调用涉及到变量的调用范围,专业术语叫变量的作用域。

0
回复
2021-04-18 15:59
@hello-no1
   其实程序的运行不就和眼前的滚滚长江水一样吗?流动的长江水必然有其源头以及尽头。长江水在流经不同地貌时,会产生很多的支流,不同的支流又会分化出诸多小支流。支流中有些绕过一段河道后又重新汇入长江,有些则成了一潭死水。   如果从江水的源头与尽头看,我们可以粗略地认为长江是以直线的运动轨迹川流不息。看看长江的各个支流,我们可以说这是长江的流动分支。再瞧瞧江水绕过的各个湾湾码头,这不是在循环往复吗?   再看看程序的运行,不也是一样吗。整体上看,程序从上往下依次执行,再执行过程中根据不同条件分化出诸多的节点,有些节点执行一次即可,有些节点需要执行多次,有些节点则直接跳过。   至此,程序的框架终于清晰了,再结合书本专业知识,我们总算弄通了程序是怎么运行的。   程序是由顺序结构,分支结构以及循环结构组成的。如果对汇编语言有所了解或者熟悉C语言goto关键字的用法,我们甚至可以说程序语言只有一种结构,那就是跳转结构。再深入一点,若理解了指针的概念,同时懂得一点计算机的组成原理,我们满可以说,程序的本质就是通过合理地规划内存,最大限度发挥计算机内部各功能模块的性能。
    不管何种程序语言,均由三种基本结构组成。他们是顺序结构,选择(分支)结构,循环结构。拿到一份写好的源码,我们首先会浏览一遍。通常的做法是从上到下快速滚动阅读一遍,熟悉程序的大体框架。从总览的高度看,CPU执行程序是从头至尾依次执行的,我们可以说从全局的角度看,程序是由不同的功能语句组成的顺序结构。

    类人猿之所以能够进化为人类,我的理解是它们具备不断试错不断学习的能力。在进化的道路中每一次试错都伴随着一次成长过程。在缓慢的成长过程中,其心志得到不断的进化当积累到一定程度,量变引起质变,类人猿终于成长为今天的你我。将人类的进化过程映射到计算机技术上,虽有些扯,但多少有些相通性。   

0
回复
2021-04-18 15:59
@hello-no1
   其实程序的运行不就和眼前的滚滚长江水一样吗?流动的长江水必然有其源头以及尽头。长江水在流经不同地貌时,会产生很多的支流,不同的支流又会分化出诸多小支流。支流中有些绕过一段河道后又重新汇入长江,有些则成了一潭死水。   如果从江水的源头与尽头看,我们可以粗略地认为长江是以直线的运动轨迹川流不息。看看长江的各个支流,我们可以说这是长江的流动分支。再瞧瞧江水绕过的各个湾湾码头,这不是在循环往复吗?   再看看程序的运行,不也是一样吗。整体上看,程序从上往下依次执行,再执行过程中根据不同条件分化出诸多的节点,有些节点执行一次即可,有些节点需要执行多次,有些节点则直接跳过。   至此,程序的框架终于清晰了,再结合书本专业知识,我们总算弄通了程序是怎么运行的。   程序是由顺序结构,分支结构以及循环结构组成的。如果对汇编语言有所了解或者熟悉C语言goto关键字的用法,我们甚至可以说程序语言只有一种结构,那就是跳转结构。再深入一点,若理解了指针的概念,同时懂得一点计算机的组成原理,我们满可以说,程序的本质就是通过合理地规划内存,最大限度发挥计算机内部各功能模块的性能。
    想要让计算机执行不同的功能,最终必然需要将不同的功能转化为计算机能够识别的语句。计算机之所以能够根据外界的变化执行不同的动作,恰恰是因为它具备试错能力,也即是判断能力。任何形式的程序语言都必须具备根据不同条件执行不同语句的能力,此形式被描述为程序语言的选择结构。

    某种意义上说,循环结构是特殊的选择结构。程序语言根据条件判断依次往下执行时,我们说这是典型的选择结构。当程序语言根据条件判断执行若干动作后,又回至条件判断的起点,重新进入条件判断的流程,依此往复执行…… 我们可以说这就是循环结构。

    从上述角度解读,我们可以认为循环结构是特殊的选择结构。当然,如果循环结构的判断执行条件仅只执行一次,我们同样可以说选择结构是特殊的循环结构。换句话说,选择结构和循环结构之间可以相互转换。

0
回复
2021-04-19 21:08

    不管是代码区还是数据区中的数据自始至终都驻扎在内存中,而内存规划的初衷是为了高效利用内存,及时回收释放多余的内存,使有限的内存有足够的空间支撑程序的全过程运行,显然仅仅靠代码区及数据区远远不够,遂引入堆和栈的概念。
    堆区(heap),该区域可看作是一个存储数据的大容器,其容量远远大于后面要讲解的栈区,该区域中的数据不需要像栈区那样遵循先进后出的规则。

    堆区主要用于动态内存分配。堆区在内存中位于数据区中的BSS区和栈区之间。该区域一般由程序员手动分配和释放,若程序员不释放,程序结束时由操作系统回收(该话题涉及到操作系统内存回收的话题,此处一笔带过,有机会分析嵌入式linux系统时讲解)。

    C语言中堆区的大小可使用malloc函数进行分配,堆区的释放采用free函数实现。程序中malloc等内存分配函数的使用次数一定要和free函数相等,并一一配对使用。否则随着程序的运行会出现内存泄漏的问题。

0
回复
2021-04-19 22:12

    栈区(stack),用于存储所有的局部变量,包括用户定义的auto型局部变量,函数的实参,返回值,嵌套函数的调用(递归函数)等。栈区和其他三个区域最大的不同点在于其采用的是先进后出的内存结构。局部变量在该区域由编译器在程序运行过程中实时加载和释放。所以局部变量的生存周期很短,需要时即申请,不用即销毁释放。

    auto型局部变量经编译器自动放入栈中后,其生存周期及作用域只限于定义的功能函数内有效,当一个auto型局部变量超出其作用域时,自动从栈中弹出,用完后再由操作系统自动释放。

    auto型局部变量的生存周期及作用域的特点牵出一个很有意思的话题,即函数实参的调用是否影响对应变量的数值,答案是不影响(后续C语言语法章节会详细讲解)。

    另外一个注意事项是不要返回局部变量的地址,因为栈区开辟的地址空间由编译器自动释放,当auto型局部变量失效后,原先对应的地址空间也随之释放,返回的局部变量地址是一个随机数,而不是之前对应的局部变量的地址。


0
回复
2021-04-19 22:20

    上述堆区和栈区的概念是针对C语言而言,对于单片机我们也经常提到堆栈的概念,但C语言的堆区栈区和单片机的堆栈还是有区别的。单片机的堆栈实质是C语言中栈的描述。通常单片机的内存资源相当有限,所以一般不分配堆区,而且很少用到标准库的malloc类函数,当然上升到操作系统层面就是另一说了。

    单片机的堆栈也属于内存的一部分,所以它肯定有临时存储的功能,那单片机的堆栈主要用于哪些存储场合呢?如果说代码区和数据区中的数据是用于单片机自始至终的全程数据存储,那堆栈就是用于单片机运行过程中的中间数据处理。

通俗的说,代码区和数据区中存储的数据只要单片机不掉电,其中的数据就不会被释放。而堆栈中的数据是根据程序需要实时产生,实时释放,我们通常提到的内存回收与释放实质是针对堆栈中数据的回收释放操作。

0
回复
鲁珀特
LV.4
31
2021-04-20 11:53

关于内存占用  我有深刻的经历,在实际使用中,内存会泄露,如果不能及时释放,很容易造成程序卡顿,运行速度变慢。

0
回复