Q: 宏有什么不好吗?
A: 宏不遵循C++的作用域和类型规则,这会带来许多麻烦。因此,C++提供了能和语言其它部分“合作愉快”的替代机制,比如内联函数、模板、名字空间机制。让我们来看这样的代码:
#include "someheader.h"
struct S {
int alpha;
int beta;
};
如果有人(不明智地)写了一个叫“alpha”或者“beta”的宏,那么这段代码无法通过编译,
甚至可能更糟——编译出一些你未曾预料的结果。比方说:如果“someheader.h”包含了
如下定义:
#define alpha 'a'
#define beta b[2]
那么前面的代码就完全背离本意了。
把宏(而且只有宏)的名称全部用大写字母表示确实有助于缓解问题,但宏是没有语言级保护机制的。例如,在以上例子中alpha和beta在S的作用域中,是S的成员变量,但这对于宏毫无影响。宏的展开是在编译前进行的,展开程序只是把源文件看作字符流而已。这也是C/C++程序设计环境的欠缺之处:程序员和编译器看到的源文件是不同的。
不幸的是,你无法确保其他程序员不犯你所认为的“愚蠢的”错误。比方说,近来有人告诉我,他们遇到一个含“goto”语句的宏。我见到过这样的代码,也听到过这样的论点——有时宏中的“goto”是有用的。例如:
#define prefix get_ready(); int ret__
#define Return(i) ret__=i; do_something(); goto exit
#define suffix exit: cleanup(); return ret__
void f()
{
prefix;
// ...
Return(10);
// ...
Return(x++);
//...
suffix;
}
如果你是一个负责维护的程序员,这样的代码被提交到你面前,而宏定义(为了给这个“戏法”增加难度而)被藏到了一个头文件中(这种情况并非罕见),你作何感想?是不是一头雾水?
一个常见而微妙的问题是,函数风格的宏不遵守函数参数调用规则。例如:
#define square(x) (x*x)
void f(double d, int i)
{
square(d); // fine
square(i++); // ouch: means (i++*i++)
square(d+1); // ouch: means (d+1*d+1); that is, (d+d+1)
// ...
}
“d+1”的问题可以通过给宏定义加括号解决:
#define square(x) ((x)*(x)) /* better */
但是,“i++”被执行两次的问题仍然没有解决。
我知道有些(其它语言中)被称为“宏”的东西并不象C/C++预处理器所处理的“宏”那样缺陷多多、麻烦重重,但我并不想改进C++的宏,而是建议你正确使用C++语言中的其他机制,比如内联函数、模板、构造函数、析构函数、异常处理等。
原文地址:http://www.research.att.com/~bs/bs_faq2.html#macro
本文乃网上搜集得来,其版权归原作者和原出处所有。如有侵犯版权之处请与我联系,我将马上进行处理。