Effective C++——》条款2:尽量以const,enum,inline替换#define .

这个条款或许可以改为“宁可 以编译器替换预处理器”。即尽量少用预处理。

 

编译过程:.c文件--预处理-->.i文件--编译-->.o文件--链接-->bin文件

 

预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。检查包含预处理指令的语句和宏定义,并对源代码进行相应的转换。预处理过程还会删除程序中的注释和多余的空白字符。可见预处理过程先于编译器对源代码进行处理。预处理指令是以#号开头的代码行。

第一部分对于常量用const和enum替换不带参宏

宏定义#define发生在预编译期,而const,enum定义的常量发生在编译期,两者的重要差别在于编译期里的变量进符号表的,而预编译期的宏简单的替换,不进符号表。因此,const, enum定义的常量具有以下优势:

(1)支持类型检查

(2)支持访问权限

 

第(1)条优势,其实在Visual Studio编译器也已经对宏也引入了类型检查了,但不是所有的编译器都这样;

第(2)条优势是指可以把这些常量放在类中,从而避免了全局的作用域而宏定义只能是全局的(全局变量在多线程中容易出问题,一份优秀的代码里是几乎不出现全局变量的),所以这条优势其实是const和enum替换宏定义最好的理由。

在书中还提到了,用const和enum定义的常量名还会出现在编译器的提示信息里,而宏定义在编译器中显示的就不是宏定义名了,而直接是一个数字量了,这样就不方便调试了

 

那么什么时候用const,什么时候用enum呢?const适合单个常量,比如double const PI = 3.1415926,而enum适合一组相关的常量,比如星期:

enum DayOfWeek
{
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
};

 

这段枚举定义了Sunday = 0, Monday = 1, …, Saturday = 6(去掉DayOfWeek也行,这时就定义了匿名的枚举类型了)。

 

第二部分对于函数用inline替换带参的宏

不带参的宏还说得过,带参的宏本身就是一个坑,可谓是bug四伏,一个不小心,就掉坑里了。举个最简单的例子:

#define square(a) a * a

在main函数中调用时,可能会这样square(3),计算的是3的平方,这是OK的,但如果换成是square(1+2),计算的还是3的平方吗?注意这时编译器解释成1 + 2 * 1 + 2,这样2 * 1的优先级高一些,所以先做了,这就出问题了。

好的,这是常见的错误,有些程序员可能认为多加括号就行,比如:

#define square(a) (a) * (a)

这的确可以避免上面所说的优先级的问题,但万一调用时是这样写的呢?

int main()
{
    int v = 3;
    squre(++v);
}

本意是想求4的平方,但编译器会翻译成(++v)*(++v),这样v就被加了两次,这个结果肯定不是你想要的!

一句话,带参的宏很容易出问题,特别是针对复合操作(一句话做了不止一件事情)时,bug频出。

 

解决这个问题的方法是:用函数替换!因为函数调用时,若实参是表达式,总是会先计算这个表达式的值,再去进行调用的,不会出现宏展开时的bug。

template <class T>
T square(const T& v)
{
    return v * v;
}

就是一种比较好的解决方案(注意这里v不用加括号了,也不用担心参数被求值多次,而且提供了可靠的作用域限制),但函数调用有一个保存现场和恢复现场的过程(本质是栈的压入和弹出),频繁地调用会导致性能低下,解决方法是在函数前面加上inline关键字,像这样:

template <class T>
inline T square(const T& v)
{
    return v * v;
}

这样就告诉编译器了,我想牺牲空间换时间——把这段函数体部分直接替换到原代码中,就不要保存现场和恢复现场了。但这里注意,inline并不是强制的,就算你用了inline,编译器也不一定100%地进行代码替换,比如递归函数,编译器会直接忽略掉你加的inline。所以,inline只是向编译器建议进行代码内联而已,inline适合于函数体本身短小(无递归)且频繁调用的场景

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值