找回密码
 立即注册
收起左侧

C++老鸟日记029 你确定要使用宏吗?

3
回复
5589
查看
[复制链接]
累计签到:41 天
连续签到:1 天
来源: 原创 2018-9-22 12:36:07 显示全部楼层 |阅读模式

马上注册,查看详细内容!注册请先查看:注册须知

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 baizy77 于 2018-10-1 20:59 编辑

版权声明
---------------------------------------------------------------------------------------------------------------------
该文章原创于Qter开源社区(www.qter.org
作者: 女儿叫老白 (白振勇)
转载请注明出处!
---------------------------------------------------------------------------------------------------------------------
本套课程属于:《C++跨平台开发干货》系列课程。
-----------------------------------------------------------------------------

引言:
----------------------------------------------------------------------------
       C++中的预处理宏提供了一种手段,可以供我们预先定义一些字符串来代替代码。但是,您知道吗,使用预处理宏经常回带来一些意想不到的问题,现在我们来一起看一下。

正文:
----------------------------------------------------------------------------
       使用预处理宏时会有几个潜在的风险:
       1. 编写代码时笔误,导致宏中间有空格,比如:
本来是:
#define PLUSX(x)  (x+1)
却因笔误,写成了:
#define PLUSX  (x) (x+1)  
       请注意PLUSX 跟(x)之间有空格
       那么,PLUSX(2),展开后变成:
              (x)  (x+1)(2)
       这不是我们所期望的结果。
       2. 忽视了运算符优先级的问题,
              #defineJUDGE(X, y)  (x>y ? 1 : 0)
       假定,我们传入JUDGE(a&0x1,0xf),展开后,变成:
       (a&0x1 > 0xf ? 1 :  0)
              但是因为>的优先级高于&,所以 变成了 a& (0x1 > 0xf),这也不是我们所期望的,解决的方法是使用括号确定优先级,比如上面的宏改成:
              #define JUDGE(x, y)  (((x) > (y)) ? 1 : 0)
3. 本来想把宏当作函数用,但是却忽视了宏定义与函数的区别。
              #defineSECTION_JUDGE(X)  ((((x)>1) &&((x)<3)) ? 1 : 0)
       如果我们传入SECTION_JUDGE(++b),那么宏展开后变成:
       ((((++b)>1) && ((++b)<3)) ?1 : 0
              这也不是我们所期望的,我们本来期望传入的值为b+1,然后b就不变了,但是使用这个宏之后,b自加了两次。
       建议所有宏采用全部大写字母命名,也是为了降低这种风险,因为一看到代码就知道这是一个宏定义,从而加倍小心。
       有时候,我们使用宏是因为它可以在调用处随时展开,没有函数调用的开销;而内联函数也具备这样的特性。内联函数也是在调用处展开代码,也没有函数调用开销。从这个意义上来说,建议大家永远不使用宏,只使用内联函数。

结语:
----------------------------------------------------------------------------
       宏定义有它的好处,比如缩短代码,降低函数调用开销等。但是一不小心就会带来潜在的问题,因此使用时要加倍小心。我个人不太倾向使用宏,如果使用常量,我一般使用下面的方法:
static const double c_PI = 3.1415927
       有不少其他的替代方案可以取代宏定义的方案,因此,我们要开阔一下思路。祝大家在使用宏时一切顺利。

参考资料
----------------------------------------------------------------------------
《C++编程思想》两卷合订本中文版(9.1章节,以及P208, P210.),(美) Bruce Eckel  Chuck Allison著


回复

使用道具 举报

累计签到:436 天
连续签到:1 天
2018-9-22 22:55:45 显示全部楼层
现在定义编译期常量用 constexpr 有更清晰严格的语义
回复 支持 反对

使用道具 举报

累计签到:41 天
连续签到:1 天
2018-9-23 22:15:32 显示全部楼层
miroox 发表于 2018-9-22 22:55
现在定义编译期常量用 constexpr 有更清晰严格的语义

您说的非常正确,从C++11开始,支持constexpr,它从语法上扩充了常量的定义,也支持地址类型常量。它定义了一种编译器可确定的常量,可以任由编译器进行优化。
回复 支持 反对

使用道具 举报

累计签到:50 天
连续签到:1 天
2018-9-24 12:00:14 显示全部楼层
已经学习                c语言中,   宏常量都可以用枚举来实现, 但是宏函数就好说了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了