1 带参数宏定义易出现的隐藏bug和定义方式归纳-德赢Vwin官网 网
0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

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

3天内不再提示

带参数宏定义易出现的隐藏bug和定义方式归纳

嵌入式那些事 来源:嵌入式那些事 2023-10-20 15:26 次阅读

宏定义尤其是带参数的宏定义,特别容易出现一些隐藏问题,因为宏定义在预处理阶段是按照定义原封不动的进行展开,此时如果展开之后涉及到运算符优先级的问题,那么隐藏bug就此出现。

这里我先列举一个简单的例子,然后归纳下带参数宏定义对于括号使用的一些说明。

1.构造带有隐藏bug的宏定义

下面定义两个带参数宏,MUL_TWO是将两个数进行相乘,MUL_THREE是将三个数进行相乘。

#defineMUL_TWO(val1,val2)(val1*val2)
#defineMUL_THREE(x,y,z)(MUL_TWO(x,y)*z)

比如我这里计算2 * 3 * 4的运算结果,那么只需调用宏MUL_THREE(2, 3, 4)就可得到计算结果为:24,计算结果是正确的。但是如果将MUL_THREE(2, 3, 4)修改为MUL_THREE(1+1, 1+2, 1+3),此时的运算结果又是多少呢,很简单,我们将这个宏进行展开,展开的过程如下所示:

MUL_THREE(1+1,1+2,1+3)=>(MUL_TWO(1+1,1+2)*1+3)
(MUL_TWO(1+1,1+2)*1+3)=>((1+1*1+2)*1+3)

然后我们计算下,得出结果是7,是不是计算错误了。

2.改造上述宏定义

这里的宏定义还是比较简单的,并且大多数的小伙伴应该都知道在定义带参数的宏时,参数需要使用括号括起来,那么我们改造下上述的宏,改造结果如下所示:

#defineMUL_TWO(val1,val2)((val1)*(val2))
#defineMUL_THREE(x,y,z)(MUL_TWO(x,y)*z)

此时再来对MUL_THREE(1+1, 1+2, 1+3)进行展开,展开的过程如下所示:

MUL_THREE(1+1,1+2,1+3)=>(MUL_TWO(1+1,1+2)*1+3)
(MUL_TWO(1+1,1+2)*1+3)=>(((1+1)*(1+2))*1+3)

然后我们计算下,得出结果是9,计算结果还是有问题。仔细检查下宏定义,原来是对MUL_THREE宏的z没有用括号括起来,这个问题也是比较容易犯的,修改好之后的宏如下所示:

#defineMUL_TWO(val1,val2)((val1)*(val2))
#defineMUL_THREE(x,y,z)(MUL_TWO(x,y)*(z))

此时再来对MUL_THREE(1+1, 1+2, 1+3)进行展开,展开的过程如下所示:

MUL_THREE(1+1,1+2,1+3)=>(MUL_TWO(1+1,1+2)*(1+3))
(MUL_TWO(1+1,1+2)*(1+3))=>(((1+1)*(1+2))*(1+3))

此时的计算结果就是没问题的了。

这里我再提个问题,为什么你在MUL_THREE宏中,只使用括号括起了z,为啥x和y你不同等对待,确实哈,如果对于不是很熟悉的小伙伴,可能看到我说的情况,会毫不犹豫的也对x和y进行同样的保护;也有的小伙伴看到我说的这个情况可能脑子里面就晕了。

3.带参数宏定义对于括号使用的一些说明

其实不对x和y做保护是有一个前提的,那就是你所定义的每一个宏定义都要确保对在当前宏中使用到的参数用括号进行保护。不知道各位明白我的意思不,不明白的话,看看我下面的总结吧。

带参数宏定义,对于括号何时使用的总结:

(1).带参数宏定义,如果参数在当前的宏中有进行运算,那么必须对该参数使用括号括起来(类似例子中MUL_THREE里面的z,MUL_TWO里面的val1和val2);

(2).带参数宏定义,如果参数没有在当前的宏中有进行运算,而是直接当成参数传递给其他的宏,那么该参数是不用使用括号进行保护的(类似例子中MUL_THREE里面的x和y)。

对于上面的总结第(2)点,能够对传递给其他宏的参数不进行括号保护是因为总结的第(1)点已经对宏做了一个规定,只要所有的宏定义都按照第(1)点进行书写,那么第(2)点自然也就不会出什么问题。







审核编辑:刘清

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

    关注

    180

    文章

    7604

    浏览量

    136678
  • Mul
    Mul
    +关注

    关注

    0

    文章

    5

    浏览量

    7957
  • 宏定义
    +关注

    关注

    0

    文章

    50

    浏览量

    9003

原文标题:C语言-带参数宏定义易出现的隐藏bug和定义方式归纳

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

收藏 人收藏

    评论

    相关推荐

    C语言定义使用技巧

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

    C语言定义与枚举类型知识

    定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了。在简单的程序使用参数定义可完成函数调用的功能,又能减少系统开销,
    发表于 10-11 17:34 1590次阅读

    C语言中常用的定义

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

    请问FLASH 的定义是如何定义的?为什么?

    ,"ramfuncs");#pragma CODE_SECTION(OffsetISR,"ramfuncs");#endif但是这个FLASH 的定义不知在哪里进行
    发表于 06-11 07:42

    C语言定义使用技巧

    写好C语言,漂亮的定义很重要,使用定义可以防止出错,提高可移植性,可读性,方便性 等等。下面列举一些成熟软件中常用得
    发表于 11-13 12:04 36次下载

    内联函数和定义的区别介绍

    定义是C语言提供的三种预处理功能的其中一种,这三种预处理包括:定义、文件包含、条件编译。定义
    发表于 12-15 15:33 2338次阅读
    内联函数和<b class='flag-5'>宏</b><b class='flag-5'>定义</b>的区别介绍

    不带参数定义是什么?不带参数定义的资料介绍详细过程概述

    c语言中有一个定义,其中有一类就是不带参数定义
    发表于 09-04 15:38 5次下载

    当使用参数调用时,会将参数替换为主体

    在大多数定义示例中,每次出现参数名称都带有括号,并且另一对括号通常会包围整个
    的头像 发表于 11-16 16:41 2311次阅读

    对于定义与重复定义的问题

    对于定义与重复定义的问题
    发表于 11-29 18:21 1次下载
    对于<b class='flag-5'>宏</b><b class='flag-5'>定义</b>与重复<b class='flag-5'>定义</b>的问题

    C语言定义--单片机中断

    在单片机中断中可以使用定义代替函数,减小系统运行时间。1.参数定义的优点:用
    发表于 01-13 12:52 6次下载
    C语言<b class='flag-5'>宏</b><b class='flag-5'>定义</b>--单片机中断

    C语言中的定义

    #define命令是C语言中的一个定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为名,被定义的字符串称为替换文本。命令有两种
    的头像 发表于 09-28 16:05 3446次阅读
    C语言中的<b class='flag-5'>宏</b><b class='flag-5'>定义</b>

    C语言定义的使用原理

    使用STM32开发的朋友不知道是否有发现过这样的一些定义
    的头像 发表于 02-01 14:36 1597次阅读

    c语言定义可以嵌套吗?

    某些代码或表达式替换为指定的字符串,从而使程序更加灵活和可读性更高。定义的语法形式为: #define 名(参数列表) 体 其中,
    的头像 发表于 09-04 17:38 3169次阅读

    c语言参数定义

    c语言参数定义  C语言定义是一种替换机制
    的头像 发表于 09-04 17:45 2399次阅读

    define定义

    define定义 以#号开头的都是编译预处理指令,它们不是C语言的成分,但是C程序离不开它们,#define用来定义一个,程序在预处理阶段将用define
    的头像 发表于 11-24 15:35 866次阅读