打印
[其他ST产品]

(分享)谈一谈嵌入式C编程中全局变量问题

[复制链接]
1877|39
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
stormwind123|  楼主 | 2023-8-8 16:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
工作也有些年头了,从一位技术新人成长到现在自诩小牛级别的人物,少不了要自己寻找资料阅读。论坛上、书店里、杂志上......要嘛是些菜鸟浅薄的自炫处女贴,要嘛是高屋建瓴云里来雾里去的概念文,好不容易遇到个实践型高手写的文章,却在渐入佳境之际嘎然而止。本是隔靴搔痒,看完后心中更是郁结不已。也罢,今日且强装回大牛,献丑谈一谈嵌入式C编程中全局变量问题。
    嵌入式特别是单片机os-less的程序,最易范的错误是全局变量满天飞。这个现象在早期汇编转型过来的程序员以及初学者中常见,这帮家伙几乎把全局变量当作函数形参来用。在.h文档里面定义许多杂乱的结构体,extern一堆令人头皮发麻的全局变量,然后再这个模块里边赋值123,那个模块里边判断123分支决定做什么。每当看到这种程序,我总要戚眉变脸而后拍桌怒喝。没错,就是怒喝。我不否认全局变量的重要性,但我认为要十分谨慎地使用它,滥用全局变量会引申带来其它更为严重的结构性系统问题。诸位看官,且听我细细道来    1. 它会造成不必要的常量频繁使用,特别当这个常量没有用宏定义“正名”时,代码阅读起来将万分吃力。
    2. 它会导致软件分层的不合理,全局变量相当于一条快捷通道,它容易使程序员模糊了“设备层”和“应用层”之间的边界。写出来的底层程序容易自作多情地关注起上层的应用。这在软件系统的构建初期的确效率很高,功能调试进度一日千里,但到了后期往往bug一堆,处处“补丁”,雷区遍布。说是度日如年举步维艰也不为过。    3. 由于软件的分层不合理,到了后期维护,哪怕仅是增加修改删除小功能,往往要从上到下掘地三尺地修改,涉及大多数模块,而原有的代码注释却忘了更新修改,这个时候,交给后来维护者的系统会越来越像一个“泥潭”,注释的唯一作用只是使泥潭上方再加一些迷烟瘴气。    4. 全局变量大量使用,少不了有些变量流连忘返于中断与主回圈程序之间。这个时候如果处理不当,系统的bug就是随机出现的,无规律的,这时候初步显示出病入膏肓的特征来了,没有大牛来力挽狂澜,注定慢性死亡。    无需多言,您已经成功得到一个畸形的系统,它处于一个神秘的稳定状态!你看着这台机器,机器也看着你,相对无言,心中发毛。你不确定它什么时候会崩溃,也不晓得下一次投诉什么时候道理。现实层面的后果是什么    1.“老人”气昂昂,因为系统离不开他,所有“雷区”只有他了然于心。当出现紧急的bug时,只有他能够搞定。你不但不能辞退他,还要给他加薪。    2. 新人见光死,但凡招聘来维护这个系统的,除了改出更多的bug外,基本上一个月内就走人,到了外面还宣扬这个公司的软件质量有够差够烂。    3.随着产品的后续升级,几个月没有接触这个系统的原创者会发现,很多雷区他本人也忘记了,于是每次的产品升级维护周期越来越长,因为修改一个功能会冒出很多bug,而按下一个bug,会弹出其他更多的bug。在这期间,又会产生更多的全局变量。终于有一天他告诉老板,不行啦不行啦,资源不够了,ram或者flash空间太小了,升级升级。    4. 客户投诉不断,售后也快崩溃了,业务员也不敢推荐此产品了,市场份额越来越小,公司形象越来越糟糕。要说对策,只有两个原则    1. 能不用全局变量尽量不用,我想除了系统状态和控制参数、通信处理和一些需要效率的模块,其他的基本可以靠合理的软件分层和编程技巧来解决。    2. 如果不可避免需要用到,那能藏多深就藏多深。    1)如果只有某.c文件用,就static到该文件中,顺便把结构体定义也收进来;    2)如果只有一个函数用,那就static到函数里面去;    3)如果非要开放出去让人读取,那就用函数return出去,这样就是只读属性了;    4)如果非要遭人蹂躏赋值,好吧,我开放函数接口让你传参赋值;5)实在非要extern**我,我还可以严格控制包含我.h档的对象,而不是放到公共的includes.h中被人围观,丢人现眼。    如此,你可明白我对全局变量的感悟有多深刻。悲催的我,已经把当年那些“老人”交给我维护的那些案子加班全部重新翻写了。你能明白吗,不要让人背后唾弃你哦。最后补充一下意见    1.全局变量是不可避免要用到的,每一个设备底层几乎都需要它来记录当前状态,控制时序,起承转合。但是尽量不要用来传递参数,这个很忌讳的。    2.尽量把变量的作用范围控制在使用它的模块里面,如果其他模块要访问,就开个读或写函数接口出来,严格控制访问范围。这一点,C++的private属性就是这么干的。这对将来程序的调试也很有好处。C语言之所以有++版本,很大原因就是为了控制它的灵活性,要说面向对象的思想,C语言早已有之,亦可实现。    3.当一个模块里面的全局变量超过3个(含)时,就用结构体包起来吧。要归0便一起归0,省得丢三落四的。    4.在函数里面开个静态的全局变量,全局数组,是不占用栈空间的。只是有些编译器对于大块的全局数组,会放到和一般变量不同的地址区。若是在keil C51,因为是静态编译,栈爆掉了会报警,所以大可以尽情驰骋,注意交通规则就是了。    5.单片机的os-less系统中,只有栈没有堆的用法,那些默认对堆分配空间的“startup.s”,可以大胆的把堆空间干掉。    6.程序模型?如何分析抽象出来呢,从哪个角度进行模型构建呢?很愿意聆听网友的意见。本人一直以来都是从两个角度分析系统,事件--状态机迁移图 和 数据流图,前者分析控制流向,完善UI,后者可知晓系统数据的缘起缘灭。这些理论,院校的《软件工程》教材都有,大家不妨借鉴下。只不过那些理论,终究是起源于大型系统软件管理的,牛刀杀鸡,还是要裁剪一下的。

使用特权

评论回复
评论
木子李惠 2023-8-9 12:24 回复TA
@xzy568 :单片机你还用Python 你还真有钱 
xzy568 2023-8-9 10:45 回复TA
@ColeYao :直接用Python不更好,可以放飞自我,如果只是做玩具的话 
ColeYao 2023-8-9 10:40 回复TA
既然嵌入式C用起来不方便,为啥不改为嵌入式Cpp! 
沙发
田舍郎| | 2023-8-8 22:23 | 只看该作者
长篇大论

使用特权

评论回复
板凳
henangongda123| | 2023-8-8 23:52 | 只看该作者
我司招研发助理电子工程师1-2名,无底薪、合作&合伙人模式,来去自由,时间自由,公开、公平、公正搞钱、分钱,手把手教PCB电路板设计和单片机程序设计,欢迎有兴趣、志同道合的朋友一起来发展,应届毕业生优先考虑!
怎么分钱说一下,比如公司接到一个案子,开发费一万,你会画板就分四分之一,既会画板又会写程序,分四分之二,样品技术员做BOM、样品分四分之一,公司留四分之一;案子开发成功,量产了,净利润分三分之一,公司专职采购、跟单员分三分一,最后公司留三分之一,公平公正公开,干了活就有钱分!大家互相配合,把案子做快、做好,慢慢案子积累多了,月入过万很轻松!

使用特权

评论回复
地板
yangxiaor520| | 2023-8-9 08:07 | 只看该作者
从变量定义和使用就可以看出一个人的编程能力

使用特权

评论回复
5
asdsfgwsafd| | 2023-8-9 08:53 | 只看该作者
大量全局变量传递参数,函数独立运行,能出BUG但不会挂。为了省date空间函数到处互相调用才是程序跑飞的诀窍

使用特权

评论回复
6
jobszheng| | 2023-8-9 10:41 | 只看该作者
天啊,你们居然阅读下来!
这一坨,排版也这样了,反正我是没有读下来

使用特权

评论回复
7
xzy568| | 2023-8-9 10:42 | 只看该作者
很好的总结,确实能不用全局变量尽量不用全局变量

使用特权

评论回复
8
ayb_ice| | 2023-8-9 13:36 | 只看该作者
一处修改,多处可读,其实也不可怕

使用特权

评论回复
9
xch| | 2023-8-9 13:55 | 只看该作者
我公司有个4k 装得下的代码产品,被楼主这种工程师维护了一下,变成16k才装得下。还出了一大堆BUG。

使用全局变量有个出BUG的绝活是数据传输和使用并不同时,没法保证一致性,脱裤子放屁还搞得一哭档屎。。

使用特权

评论回复
10
xch| | 2023-8-9 14:24 | 只看该作者
以后可以写一篇论文,坐马桶敲代码质量高。姿势正确很重要。

使用特权

评论回复
11
elephant00| | 2023-8-9 15:18 | 只看该作者
xch 发表于 2023-8-9 14:24
以后可以写一篇论文,坐马桶敲代码质量高。姿势正确很重要。

你的灵感都源自于马桶是吧,哈哈

使用特权

评论回复
12
xzy568| | 2023-8-9 17:05 | 只看该作者
xch 发表于 2023-8-9 13:55
我公司有个4k 装得下的代码产品,被楼主这种工程师维护了一下,变成16k才装得下。还出了一大堆BUG。

使用 ...

这不可能吧,很难理解代码长度变更如此之长是这个原因

使用特权

评论回复
13
xch| | 2023-8-9 18:59 | 只看该作者
xzy568 发表于 2023-8-9 17:05
这不可能吧,很难理解代码长度变更如此之长是这个原因

你写个I2C 接口E2PROM 读写驱动。需要占用几个字节FLASH?288个字节能不能做出?看到驱动需要3K多,还居然不能跨页写的代码就知道可能了。本末倒置,完全是为了敲代码的姿势好看。

使用特权

评论回复
14
xzy568| | 2023-8-10 11:50 | 只看该作者
本帖最后由 xzy568 于 2023-8-10 11:53 编辑
xch 发表于 2023-8-9 18:59
你写个I2C 接口E2PROM 读写驱动。需要占用几个字节FLASH?288个字节能不能做出?看到驱动需要3K多,还居 ...

你的逻辑是因为你遇到某个人写程序很烂,所以和他一样程序架构的人,写的一定也很烂
这能算逻辑吗?你这个和有人写汇编写得很烂,比用C写的还长,因此汇编的代码不如C紧凑的逻辑是一样的

使用特权

评论回复
15
xch| | 2023-8-10 12:42 | 只看该作者
xzy568 发表于 2023-8-10 11:50
你的逻辑是因为你遇到某个人写程序很烂,所以和他一样程序架构的人,写的一定也很烂
这能算逻辑吗?你这个 ...

我的逻辑是用全局变量完成的代码,用了楼主推荐的局部变量就变得奇葩的肥大且增加了故障。

你的啥逻辑得出上述这个结论?

使用特权

评论回复
16
li880wert| | 2023-8-10 14:21 | 只看该作者
给维护了 好几个 这样的项目,includes.h  extern 全局变量满屏幕 密密麻麻

使用特权

评论回复
17
z_no1| | 2023-8-11 16:16 | 只看该作者
xch 发表于 2023-8-9 18:59
你写个I2C 接口E2PROM 读写驱动。需要占用几个字节FLASH?288个字节能不能做出?看到驱动需要3K多,还居 ...

看情况,你要用PIC这种分页的MCU,这样是有用,但在CM3这类上,不是特别紧张的资源,3K问题不大,不过I2C驱动能写到3K也是本事啊,有那么写的吗?

使用特权

评论回复
18
Stahan| | 2023-8-11 22:49 | 只看该作者
有时候全局变量也会很有用的

使用特权

评论回复
19
Stahan| | 2023-8-11 22:49 | 只看该作者
感觉不能一棍子全部打死

使用特权

评论回复
20
zhanyanqiang| | 2023-8-14 11:03 | 只看该作者
存在便是合理,总是要根据实际情况出发,只能这么说

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

416

主题

2129

帖子

2

粉丝