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

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

3天内不再提示

C语言中常见的一些大坑

鱼鹰谈单片机 来源:鱼鹰谈单片机 作者:鱼鹰Osprey 2022-04-15 08:21 次阅读

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

鱼鹰曾经因为一个很基础的知识,差点毁了整个项目,这不是危言耸听。因为这个代码用于整个系统自检,一旦运行出错,整个系统就废了。

为了不让别人篡改鱼鹰的代码,鱼鹰设计了多套机制,其中一个就是定时检查关键代码是否已执行,如果有一次没有执行,那么系统进入异常状态,这个功能类似窗口看门狗

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)


970eaf2c-bc51-11ec-aa7f-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 型处理。最终导致溢出时,结果判断失败。

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

971d5c70-bc51-11ec-aa7f-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 比较)。

972c8f56-bc51-11ec-aa7f-dac502259ad0.png

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

如果对你有帮助,欢迎转发分享支持鱼鹰,这样鱼鹰也更有动力记录原创笔记。

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

文章出处:【微信公众号:鱼鹰谈单片机】欢迎添加关注!文章转载请注明出处。

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

    关注

    180

    文章

    7597

    浏览量

    136129
  • 代码
    +关注

    关注

    30

    文章

    4742

    浏览量

    68329

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

文章出处:【微信号:emOsprey,微信公众号:鱼鹰谈单片机】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言中常用的宏定义

    写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等。下面列举一些成熟软件中常用的宏定义。
    发表于 10-18 10:05 1653次阅读

    C语言中枚举的基本概念和常见用法

    C语言中,枚举是种方便组织和表示组相关常量的工具。枚举类型有助于提高代码的可读性和可维护性。本文将介绍C
    发表于 08-17 15:32 1377次阅读

    c语言中常用的宏定义有哪些?

    c语言中常用的宏定义有哪些?
    发表于 04-28 06:01

    嵌入式C语言中常见不常用的语法有哪些

    嵌入式C语言中常见不常用的语法1. 不定参数需要包含头文件#include "stdarg.h"头文件里主要包括个变量类型va_list,三个函数va_start,va_arg
    发表于 12-15 06:34

    C语言中常见的数据溢出情况有哪些

    C语言中有几种基本数据类型呢?C语言中常见的数据溢出情况有哪些?
    发表于 02-25 07:55

    单片机C语言中常用到的关键字及数据类型

    单片机C语言中常用到的关键字及数据类型。
    发表于 11-03 10:57 13次下载

    C语言常见的问题

    本文详细介绍了关于C语言一些常见的问题及其解决方法
    发表于 08-29 14:22 3次下载

    关于C语言一些特殊功能介绍

    C语言之所以那么受欢迎,除了C语言历史悠久之外,还有它具有一些编程语言没有的功能。那么,今年我们
    的头像 发表于 08-18 15:31 2385次阅读
    关于<b class='flag-5'>C</b><b class='flag-5'>语言</b>的<b class='flag-5'>一些</b>特殊功能介绍

    C语言常见一些标准库

    有很多工程师喜欢自己封装一些标准库已有的函数,其实自己封装的函数,并不定比标准库好,有时候反而代码更冗余,且有bug。下面就来分享C语言
    的头像 发表于 11-18 16:22 3110次阅读

    C语言一些常用标准库分享

     有很多工程师喜欢自己封装一些标准库已有的函数,其实自己封装的函数,并不定比标准库好,有时候反而代码更冗余,且有bug。下面就来分享C语言
    的头像 发表于 11-22 11:54 2796次阅读

    C语言和STM32学习的一些学习笔记

    自己总结的一些C语言和STM32F1学习的一些笔记,适合想快速了解学习C语言和STM32单片机的
    发表于 03-24 14:53 36次下载

    C语言中必须要掌握的位运算操作

    C语言中,特别是在嵌入式的开发中,位操作是很常用的个知识点,涉及到按位(bit)操作的地方也是很常见的。本文分享一些
    的头像 发表于 02-10 14:19 1362次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言中</b>必须要掌握的位运算操作

    列举一些C语言中常用的宏定义

    写好C语言,使用宏定义可以防止出错,提高可移植性、可读性等。下文列举一些成熟软件中常用的宏定义。
    发表于 10-07 10:54 522次阅读
    列举<b class='flag-5'>一些</b><b class='flag-5'>C</b><b class='flag-5'>语言中常</b>用的宏定义

    如何解决C语言中的“访问权限冲突”异常?C语言引发异常原因分析

    如何解决C语言中的“访问权限冲突”异常?C语言引发异常原因分析  在C语言中,访问权限冲突异常通
    的头像 发表于 01-12 16:03 5031次阅读

    介绍C语言中错误处理和异常处理的一些常用的方法和策略

    C语言种低级的、静态的、结构化的编程语言,它没有提供像C++或Java等高级语言中的异常处理
    的头像 发表于 02-28 14:25 585次阅读