Redian新闻
>
什么,这个 C 语言大坑你没见过?

什么,这个 C 语言大坑你没见过?

公众号新闻

开发过程中,你是否会发出“基础不牢,地动山摇”的感慨,我相信,只要有经验的工程师,应该都有过。

鱼鹰曾经因为一个很基础的知识,差点毁了整个项目,这不是危言耸听。因为这个代码用于整个系统自检,一旦运行出错,整个系统就废了。
为了不让别人篡改鱼鹰的代码,鱼鹰设计了多套机制,其中一个就是定时检查关键代码是否已执行,如果有一次没有执行,那么系统进入异常状态,这个功能类似窗口看门狗
uint16_t run_cnt, run_cnt_next;
void function1(){  do something ;  run_cnt++; // 自加,表示该函数已执行}int main(){  while(1)  {    function1();    if(run_cnt != run_cnt_next + 1// 判断两个变量是否匹配    {      do error some thing    }    run_cnt_next++; // 这个位置也自加,表示这里已执行  }}
类似流程如上,当时鱼鹰为了减少变量空间,将计数器设计成了 uint16_t 类型,导致埋下了隐患。
这个流程乍一看没有问题,因为 run_cnt 比 run_cnt_next 先加,那么 run_cnt_next + 1 应该等于 run_cnt,如果不相等,作错误处理。
甚至短时间内运行不会有任何问题,除非 16 位溢出……
所以一个量产项目,任何一点改动,都可能需要长时间的稳定测试,只有这样才能确保系统稳定性,不能认为自己能力强,写的代码不用测试就直接合并了。
原先鱼鹰以为,这两个变量都是 16 位,那么 + 1 的结果应该也是16 位,最后比较时,也是 16 位比较,这样即使最终 16 位自加溢出了,结果也会是正确的。
if(run_cnt != run_cnt_next + 1) // 判断两个变量是否匹配{      do error some thing}


但你以为,终究是你以为。

实际上,因为你和  1 自加了,最终比较是按照 32 位进行比较,而 run_cnt 受到变量位数限制,始终是 16 位的结果(但扩展成 32 位比较,即高 16 位全是 0)
这样就会导致在溢出时,两者是不相等的。
比如上一次 run_cnt 为 0xFFFF 时(受位数限制,最大只能是这个),run_cnt_next 为 0xFFFE,此次结果比较即使按 32 位比较,也是没有问题的,都是 0xFFFF。
但下一次运行时,run_cnt 自加,溢出变成 0,而 run_cnt_next 是 0xFFFF,再和 1 相加,因为比较会使用 32 位比较,所以此时结果是 0x10000,最终导致两者不相等(0 != 0x10000)。
那么为什么会导致上面的问题呢?这里涉及到两个 C 语言基础知识点,估计大家以前都了解过,但估计没有当回事。
1、常量默认为 int 型(但不一定是 32 bit ,和内核和编译器有关,上面的 +1 就是 int 型)
2、整型提升(详细可网上查找)
因为两边的结果类型不一致(+ 1 导致右边结果成了 int 类型),所以最终按 int 型处理。最终导致溢出时,结果判断失败。
我们可以通过汇编看出一些端倪:
我们可以看到 r0 + 1 之后,直接和 r1 比较,也就是说,结果可能超过 0xFFFF,导致出错。

那么,怎么样才可以保证结果为 16 位呢?
我们可以这样处理:
if((uint16_t)run_cnt != (uint16_t)(run_cnt_next + 1)) // 强制转化为 16 位比较{      do error some thing}
我们可通过汇编发现,多了一条 UXTH 指令,用于把 16 位结果扩展成 32 位(从这里我们也可以得出结论,结果比较总是 32 bit 比较)。

到此,分析结束,可以看到,为了解释这么一条简单的 C 语言语句,还是挺困难的事情。
-END-

往期推荐:点击图片即可跳转阅读

这样写代码,美女同事乐开花


C++ 夺冠!2022 年度编程语言


模拟3万伏高压,MCU是否扛得住?


如何聪明地防止电源正负极接反?

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
每个孩子都是天生的语言大师,边玩边学的英语启蒙故事会投资圈大咖炮轰FA!"如果不会这些 就别沽名钓誉到处吹牛逼显得没见过世面"我,23 年没见过雪,跨越半个中国去东北滑雪翘脚牛肉、黄柿子锅、麻辣番茄锅, 西雅图你没见过的火锅, 这里都有![干货] 北京语言大学这个语言梗玩得溜~太高级了!你没见过的Yoku Moku限定礼盒,情人节甜品就选它们啦~真的每个都想试!戒色博主晒18岁边牧,说它长寿因没见过母狗…网友:也可能咽不下这口气拆开Netty,我发现了这8个从来没见过的东西完全可以裸考、含金量超高的全美奥林匹克计算语言大赛 NACLO 进入报名最后阶段!小福尔摩斯们快来报名!可别让孩子再拼奥数了!这辈子就没见过这么离谱的飞机场!以色列自驾游(3)地中海空中花园 - 海法【笑话】见过坑娃的爹,没见过坑孙的爷西游72:谁才是《西游记》中的语言大师?跟着如来学说话!三联绝美新年礼 | 一眼惊艳!保证你没见过这样的兔这里是佐治亚之巅,有你没见过的美婚庆公司,能坑你多少钱?太太去趟英国,回来升级做外婆还在花钱看“假高清”?进来看看是谁在坑你女神节将至,特别的花卉礼物保准你没见过你没见过的“春晚”神仙阵容 :钱钟书,梅兰芳,老舍,巴金全来了……畅游法国(40)-敦刻尔克行新鲜空运!东京牛奶芝士工厂,在美国没见过的口味:黑松露车打芝士饼干、鲜牛乳年轮蛋糕、蜂蜜海盐饼干!今日最佳:没见过放烟花?耶鲁法学院退出《美国新闻》的排名,哈佛也跟进没见过这么纯的哈士奇!北京语言大学 | 语言监测与智能学习研究组2023年研究生招募什么,纽约是最适合养家糊口的州?!是的,你没看错...“谁能体会我当父亲的心情?”签证9个月无消息,孩子3岁了没见过!华人控诉移民局!最后一刻部长松口,配偶工签新政“跳票”...上万人挤破头!妈妈拿香港优才,孩子躺赢?!这些坑你一定要避开完成Pre-A+轮融资,语言大模型企业「澜舟科技」推出孟子MChat可控大模型|36氪首发印度奶奶连续三年头上长“犄角”,诡异病症连医生都没见过!“没见过这么嚣张的”美国男子手持步枪冲进警察局袭警。当别人问及我不懂的事情29种口味Goldfish排名!彩虹小鱼没夺冠,这些口味你都没见过!
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。