您的位置:首页 > 编程语言 > C语言/C++

宏在C++中的替代解决方案

2012-12-23 13:10 786 查看
宏,在C语言中是个神的存在,能够玩出各种花样,也正因为此,才会给普通程序员造成不少的困扰。由于宏只在预编译阶段起作用,使得编译器无法检测其中的Bug,作为新时代的C++程序员,还是远离的好。

C++为宏提供了一些替代的解决方案,嗯,是一些。

1. 常量定义

#define NUM 100

《EffectiveC++》的第一个条款,讨论的就是这个宏。由于宏是预编译程序来处理,所以NUM这个名字不会加入到符号表中,如果出现编译错误时,提示信息中就不会出现NUM,而是100,为排除错误增加了额外的障碍。

替代方案就是使用const来定义常量,或者使用枚举enum。

const int NUM = 100;

const常量放在头文件中,也不必担心存在多个实例的问题,对于const修饰的变量,编译器一般也会对其进行优化,不会出现多重定义的问题。

C语言中还有一个特殊的常量定义:NULL。其一般的定义为 #define NULL 0,指针的内容却是一个整型,这不符合常理。所以在C++11中使用nullptr代替了NULL。

2.函数定义

由于宏只是在代码中做字符串替代展开,所以,用宏定义的函数,实际上并没有减少代码的体积。另外,还有一些天然的缺陷,假设一个求平方的函数宏

[cpp] view plaincopy

#definesquare(x) (x*x)

voidf(double d, int i)

{

square(d); //OK

square(i++); //糟糕, (i++*i++)

square(d+1); //更糟,(d+1*d+1)

}

纵然可以把参数加上括号来解决,#define square(x) ((x)*(x)),但i++被执行两次这个问题还是无法解决。

C++中的替代方案,就是使用inline函数。

[cpp] view plaincopy

inline int square(intvalue)

{

return value*value;

}

inline函数具有函数的性质,参数传递不管是传值还是传引用,都不会对参数进行重复计算;同时会对参数做类型检查,保证代码的正确性;inline函数也是在代码中做代码展开,效率上并不比宏逊色。

如果整型不满足需求,还可以定义为模板:

[cpp] view plaincopy

template<classT>

inline T square(T& value)

{

return value*value;

}

还有一种更离谱的函数定义形式:

[cpp] view plaincopy

#defineNull_Check(p)\

if(p == NULL) return;

这种使用反斜杠定义的函数,更得注意,如果在反斜杠后多了个空格的话,有的编译器会出现变异错误,而提示信息嘛,你可能会困扰很久的。因为反斜杠会对空格这个字符做反义,就会在代码中的引入非法字符,人眼是很难发现这种错误的。

3.类型重定义

#defineDWORD unsigned int

这种类型重定义完全可以使用 typedef unsigned int DWORD 来替代。

4.条件编译

[cpp] view plaincopy

#ifdefSystemA

testA();

#else//SystemB

testB();

#endif

这种条件编译宏,一般在不同的产品或平台使用同一套代码的情况,大量出现。定义了SystemA的时候,SystemB的代码是不编译的,也就意味着你的代码没有时刻处于编译器的监控中。可以使用template技术来解决。

[cpp] view plaincopy

constint SystemA = 1;

constint SystemB = 2;

template<int T>

void test()

{}

//定义不同的系统的特化版本

template<> void test<SystemA>(){ //SystemA的实现 }

template<> void test<SystemB>(){ //SystemB的实现 }

这样,不同的系统使用自己的模板即可,别人的代码也会同时接受编译器的检查,不至于出现遗漏编译错误的情况。

5.头文件包含

[cpp] view plaincopy

#ifndeftest_h

#definetest_h

//test.h的实现

#endif

为了防止头文件重复包含,C++中现在也只能这么做,目前没有别的替代方案。且看看原委,Bjarne Stroustrup在《C++语言的设计与演化》一书中,提供了一个include的设计,可惜的是并没有真正实现。(Cpp, 即C语言预处理器)

我曾经建议可以给C++本身增加一个include指示字,作为Cpp的#include的替代品。C++的这种include可以在下面三个方面与Cpp的#include不同:

1)如果一个文件被include两次,第二个include将被忽略。这解决了一个实际问题,而目前这个问题是通过#define和#ifdef,以非常低效而笨拙的方式处理的。

2)在include的正文之外定义的宏将不在include的正文内部展开。这就提供了一种能够隔离信息的机制,可以使这些信息不受宏的干扰。

3)在include的正文内容定义的宏在include正文之后的正文处理中不展开。这保证了include正文内部的宏不会包含它的编译单位强加上某种顺序依赖性,并一般地防止了由宏引起的奇怪情况。

对于采用预编译头文件的系统而言一般地说,对于那些要用独立部分组合软件的人们而言,这种机制都将是一个福音。请注意,无论如何这还只是一个思想而不是一个语言特征。

也就是说,这个想法在C++中并没有实现。

如果你没有很好的驾驭宏,那就敬而远之吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: