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)点自然也就不会出什么问题。







审核编辑:刘清

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

    关注

    180

    文章

    7533

    浏览量

    128805
  • Mul
    Mul
    +关注

    关注

    0

    文章

    5

    浏览量

    7937
  • 宏定义
    +关注

    关注

    0

    文章

    48

    浏览量

    8927

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

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

收藏 人收藏

    评论

    相关推荐

    C语言常用定义技巧(转)

    C语言常用定义技巧
    发表于 07-26 12:47

    verilog 不能定义参数扩展麻烦,有啥办法没有

    verilog 功能很弱,不能定义参数,很不方便,比如一组组合电路持续赋值:ssign wto_0 =wt[0];assign wto_1 =wt[1];assign wto_2
    发表于 10-07 10:56

    C语言定义技巧

    C语言定义技巧
    发表于 03-01 21:58

    C语言定义中#和##的作用

    定义的递归展开。可以通过中间的转换的,来实现参数的展开。测试例子:#include #include #include #defin
    发表于 08-23 18:22

    单片机定义学习笔记

    ;endifendm调用格式是BANK num (num是 0~3 代表4个BANK)PAGE num (num是 0~3 代表4个PAGE)这样方便多了,而且不会出错(2)参数作为例子,我们假定
    发表于 10-10 19:27

    定义问题!

    各位,请问一下,这个定义代表什么意思?#define OUTPUT_WAVE(pointer, d)PORTC = pointer[d*N_PORTS + 0] 谢谢
    发表于 03-12 10:30

    有关于定义的问题,涉及##和#

    想通过定义来实现,如下面格式#define link(arg) RCC_APB2Periph_##arg返回的结果为RCC_APB2Periph_GPIOC,以方便在时钟使能函数中使用请教该怎么实现——来自
    发表于 04-20 23:33

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

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

    请问C语言不同的条件怎么使用不同的定义

    碰到一个问题:需要根据一个参数的值来使用不同的定义,但是之前好像没见过if(xxx == x){#define xxxx}这种语句,有没有哪位大神有好的办法实现这个功能呢
    发表于 10-08 09:30

    ucgui配置选项定义要在哪里定义啊?

    )颜色。SCROLLBAR_COLOR0_DEFAUL 0xc0c0c0箭头按钮的颜色。SCROLLBAR_USE_3D1启用 3D 支持。如图,类似这些定义要在哪里定义啊?是guiconf.h吗?
    发表于 05-01 04:36

    定义的理解

    工程目标:实现按键长按,短按,双击,单机调用不同的回调函数,执行不同的命令。定义:#define TRIGGER_CB(event)\if(btn->CallBack_Function
    发表于 01-05 06:58

    方向寄存器DDR的定义操作

    1、对于方向寄存器DDR的定义操作不是随意的,需要满足一定的规则,比如:DDRP寄存器。2、正确的定义方式#define DATA PT
    发表于 02-17 07:36

    在单片机中断中可以使用定义代替函数吗

    在单片机中断中可以使用定义代替函数,减小系统运行时间。1.参数定义的优点:用
    发表于 02-25 06:20

    C语言定义使用do{}while(0)的好处是什么

    C语言定义使用do{}while(0)的好处1. 概述经常写项目代码,有时需要用到定义,而定义
    发表于 02-25 06:28

    c语言带参数的宏定义

    c语言带参数的宏定义  C语言宏定义是一种宏替换机制,它可以将一个标识符替换为一个代码片段。宏定义通常在程序中用来方便地进行常量定义或函数模
    的头像 发表于 09-04 17:45 1849次阅读