C++中的宏

来源:互联网 发布:走好网络群众路线 编辑:程序博客网 时间:2024/06/07 23:20


       宏在C语言里非常重要,而在C++里则很少应用。关于宏的首要规则是:除非极其必要,否则不应该去使用宏。几乎每个宏都代表了程序设计语言里,或者程序里,或者程序员的一个缺陷,因为它将在编译器看到程序的正文之前重新修改这些正文(即宏的替换)。宏也是许多程序设计工具的主要麻烦。所以,如果你使用了宏,你就应该准备着只能从各种工具(如排错系统、交叉引用工具、轮廓程序等)得到较少的服务。如果你必须使用宏,请仔细阅读你所用的C++预处理器实现的手册。还要警告读者 ,应该按照习惯,在为宏命名时尽量使用大写字母。

       简单的宏定义就像下面这样:

#define NAME rest of line
       当NAME作为一个单词被遇到时,它就会被字符序列rest of line取代。

       例如,

named = NAME
       将被展开为
named = rest of line    

       也可以定义带参数的宏,例如,

#define MAC(x, y) argument1 : x  argument2 : y
         在使用MAC时必须提供两个字符串,它们将在MAC()被展开时用于取代x和y,例如,
expanded = MAC(foo bar, yuk yuk)
          将展开成
expanded = arugment1 : foo bar  argument2 : yuk yuk
          宏名字不能重载,而且宏预处理器不能处理递归调用:

#define PRINT(a, b) cout << a << b  #define PRINT(a, b, c) cout << a << b << c    // 错误:不允许重载,编译器会提示重复定义#define FAC(n) (n > 1) ? n * FAC(n - 1) : 1   // 错误:递归的宏

       宏对字符串进行处理操作,但它对C++的语法知之甚少,根本不知道C++的类型和作用域规则。编译器能看到的只是宏展开后的形式,所以在宏中的错误是在宏被展开之后报告的,而不是在它定义的时候,这可能导致非常难以理解的错误信息。

       下面是一些可能有用的宏:

#define CASE break;case#define FOREVER for(; ;)
       下面是一些完全没有必要的宏:
#define PI 3.14#define BEGIN {#define END }
       下面是一些很危险的宏:

#define SQUARE(a) a * a#define INCR_xx (xx)++
       想知道它们为什么危险,请试着展开这个程序片段:

int xx = 0;                  // 全局计数器void f() {    int xx = 0;              // 局部变量    int y = SQUARE(xx + 2);  // y = xx + 2 * xx + 2,即y = xx + (2 * xx) + 2    INCR_xx;                 // 增加局部的xx}
       如果你要使用宏,在引用全局名字时一定要使用作用域解析运算符::,并在所有可能的地方将出现的宏参数都用括号围起来。例如,

#define MIN(a, b) (((a) < (b)) ? (a) : (b))
       通过利用宏,你可以设计出自己的私有语言。即使与C++相比你更偏爱自己的这种“增强的语言”,但对于大部分C++程序员而言,它也是不可理解的。进一步说,C预处理器是一种很简单的宏处理器。当你试图去做某些不那么简单的事情时,你多半会发现不能做好,或者做起来有不必要的困难。const,inline,template,enum和namespace机制等都是为了用作预处理器结构的许多传统使用方式的替代品。


       引用书目:Bjarne Stroustrup.贝尔实验室著《The C++ Programming Language》

               

             

原创粉丝点击