0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

关于C语言大坑你知道嘛?

Q4MP_gh_c472c21 来源:鱼鹰谈单片机 作者:鱼鹰谈单片机 2022-05-10 14:43 次阅读
在开发过程中,你是否会发出“基础不牢,地动山摇”的感慨?我相信,只要有经验的工程师,应该都有过。 鱼鹰曾经因为一个很基础的知识,差点毁了整个项目,这不是危言耸听。因为这个代码用于整个系统自检,一旦运行出错,整个系统就废了。 为了不让别人篡改鱼鹰的代码,鱼鹰设计了多套机制,其中一个就是定时检查关键代码是否已执行,如果有一次没有执行,那么系统进入异常状态,这个功能类似窗口看门狗
uint16_trun_cnt, run_cnt_next;
void function1(){dosomething;run_cnt++; // 自加,表示该函数已执行}int main(){while(1){function1();if(run_cnt!=run_cnt_next+1)//判断两个变量是否匹配{doerrorsome 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)

bca4b5e6-d016-11ec-bce3-dac502259ad0.png


这样就会导致在溢出时,两者是不相等的。

比如上一次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 型处理。最终导致溢出时,结果判断失败。

我们可以通过汇编看出一些端倪:

bcba5a9a-d016-11ec-bce3-dac502259ad0.png

我们可以看到 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 比较)。

bcd775a8-d016-11ec-bce3-dac502259ad0.png

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

END 审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7596

    浏览量

    136008
  • 代码
    +关注

    关注

    30

    文章

    4733

    浏览量

    68283

原文标题:这个C语言大坑,你见过没?

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言与Java语言的对比

    C语言和Java语言都是当前编程领域中的重要成员,它们各自具有独特的优势和特点,适用于不同的应用场景。以下将从语法特性、内存管理、跨平台性、性能、应用领域等多个方面对C
    的头像 发表于 10-29 17:31 174次阅读

    关于定位系统技术知道多少?

    定位系统在如今这个没有隐私的社会,已不是稀奇的技术。 不管是在大街上走还是在商场里逛, 只要想知道的行踪就被定位系统锁定了。就像我们看的西部大片,罪犯在这边打电话,FBI在那边定位,唧唧几声
    的头像 发表于 07-12 11:16 296次阅读
    <b class='flag-5'>关于</b>定位系统技术<b class='flag-5'>你</b><b class='flag-5'>知道</b>多少?

    按照这样学习C语言,成为卷王不是梦!

    在计算机编程领域,C语言被誉为一种强大而灵活的编程语言,掌握好C语言不仅可以让轻松驾驭各种编程
    的头像 发表于 07-06 08:04 281次阅读
    按照这样学习<b class='flag-5'>C</b><b class='flag-5'>语言</b>,成为卷王不是梦!

    PLC编程语言C语言的区别

    在工业自动化和计算机编程领域中,PLC(可编程逻辑控制器)编程语言C语言各自扮演着重要的角色。尽管两者都是编程语言,但它们在多个方面存在显著的区别。本文将从多个维度深入探讨PLC编程
    的头像 发表于 06-14 17:11 2403次阅读

    C语言中,同一个函数能不能被定义两次?

    稍微有点C语言基础的同学,一定知道不能这样做。
    的头像 发表于 05-11 18:27 1565次阅读

    c语言,c++,java,python区别

    C语言C++、Java和Python是四种常见的编程语言,各有优点和特点。 C语言
    的头像 发表于 02-05 14:11 2185次阅读

    vb语言c++语言的区别

    VB语言C++语言是两种不同的编程语言,虽然它们都属于高级编程语言,但在设计和用途上有很多区别。下面将详细比较VB
    的头像 发表于 02-01 10:20 1989次阅读

    Go编程语言-应该知道的一切

    Go 编程语言的故事始于 Google,当时三位工程师 Robert Griesemer、Rob Pike 和 Ken Thompson 对 C++ 的复杂性以及缺乏提供高效编译和执行的简单语言感到厌倦。
    的头像 发表于 12-11 17:37 602次阅读

    关于晶闸管你知道多少?

    关于晶闸管你知道多少?
    的头像 发表于 12-07 17:27 634次阅读
    <b class='flag-5'>关于</b>晶闸管你<b class='flag-5'>知道</b>多少?

    C语言运行环境是什么

    C语言运行环境(C language runtime environment)是指在执行C语言程序时所需的软件及硬件环境。
    的头像 发表于 11-27 16:13 3305次阅读

    如何选择创建c语言c++

    选择创建 C 语言C++ 都需要综合考虑多个因素。在决定使用哪种语言之前,我们需要对这两种语言的特点、优缺点、适用场景、学习成本等进行全
    的头像 发表于 11-27 15:58 563次阅读

    visualc++怎么新建c语言文件

    ++ 中新建 C 语言文件的步骤如下: 打开 Visual C++ IDE:首先,需要打开 Visual C++ 集成开发环境。
    的头像 发表于 11-27 15:57 3500次阅读

    c语言codeblocks怎么运行

    C语言中,Code::Blocks 是一个常用的集成开发环境(IDE),可以用于编写、调试和运行C语言程序。下面是关于如何在Code::B
    的头像 发表于 11-26 09:24 3688次阅读

    C语言printf函数族学习笔记

    printf 应该是学习C语言的第一个函数,我们都知道它是用于字符串格式化输出的。但是它的用法真正了解了吗?
    的头像 发表于 11-24 11:15 901次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>printf函数族学习笔记

    c语言gets函数可以输入数字吗

    C语言中的gets函数是用来读取字符串的,而不是用来读取数字的。它会读取输入的字符直到遇到换行符或者文件结束符。因此,如果尝试使用gets函数来读取数字,是无法准确获取数字本身的。 首先,让我们
    的头像 发表于 11-24 10:00 1413次阅读