正文

[转] 宏有什么不好吗?2007-11-17 18:31:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lym51/31001.html

分享到:

 

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

阅读(2539) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册