荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Dreamer (黄昏·落霞·萤火·街灯), 信区: SoftDev
标  题: 【C++】[FAQ]宏有什么不好吗?
发信站: 荔园晨风BBS站 (Wed Jun 16 14:01:23 2004), 站内信件


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++语言中的其他机制,比如内联函数、模板、构造函数、析构函数、异常处理等





--
 if (I.amOnBBS) I.OpenMyFTP();
 else { if (BBS.isShutDown) {if (rand()<RAND_MAX*3/4) I.OpenMyFTP();}
        else { if (MyMachine.hasSthWrong) I.SayHehe();
               else I.GoOutDoor();
               You.ExcuseMeFor(I.canDoNothing); }
 }

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.223]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店