Simba

博客园 首页 新随笔 联系 订阅 管理

宏定义(#define)的作用及使用方法属于C语言基础的范畴,本文不打算多做赘述,在此只是给出#define可能引起的或潜在的风险,希望对你有所帮助。

 

首先,就是常见的#define和typedef的区别,这个C语言的书都会解释,不过既然说起#define了那就顺便再写一次吧,看如下定义

#define int_ptr int *
int_ptr p_1st, p_2nd;
/**
* 程序编译经扩展后变成
*/
int * p_1st, p_2nd;
/**
* 可见p_1st是指针,而p_2nd就是一整形变量
*/

typdedef 
int * int_ptr
int_ptr p_1st, p_2nd;
/**
* 现在p_1st和p_2nd都是int类型的指针
*/

 

 

下面才是编程中#define可能会引起的黑洞,先看这个宏定义 

1 #define MAX(A, B) A > B ? A : B

 

这个宏做一个加法的运算,你觉得它有什么问题吗??看看如下的调用会发生什么情况 

1 int a = MAX(21+ 3;

 

这里就有情况了,由于运算符的优先顺序不同,那么这里并不能得到我们期望的值。好的,我们可以这样解决 

1 #define MAX(A, B) (A > B ? A : B)    // 加个括号来预防上面的问题

 

好,上面的问题现在解决了, 再看看下面的代码 

int i = 0;
int j = 2;

int a = MAX(i++, j++);

 

现在新的问题又出现了,这段代码还是不能得到我们期望的结果,可能你会说这么用的人有病吗,干吗传这么个参数,但是实际项目中的代码各式各样,出现一次就是麻烦是不是。由于这个问题,因此在C++里建议用inline函数代替宏定义,但是无论如何在C语言的项目里宏定义是非常广泛的存在的,了解一些宏的负面作用还是有助于你写出预防性的代码。

下面我们再看看#define的另外一个可能的缺陷,先看这个代码 

1 #define TEST_MACRO() \
2     DO_A(); \
3     DO_B();

 

直接使用这个宏会有问题吗,假设我们如下使用它 

1 if (something)
2    TEST_MACRO();

 

它就会扩展成这样 

1 if (something)
2    DO_A();
3    DO_B();

 

这样DO_B()原本是有条件的执行,现在是任何时候都无条件执行,视编译器而定,有的编译器能解决这种问题,但是单从C语言语法本身的角度来讲这样就有问题,依赖于编译器来解决问题是有风险的。也许你想用括号{}来解决问题,变成这样 

#define TEST_MACRO() { \
    DO_A(); \
    DO_B(); \
}

 

好,上面的问题解决了,但是如果这样定义宏并且如下使用呢:

代码
#define TEST_MACRO() { \
if (A) \
  DO_A(); \
else \
  DO_B(); \
}

如下使用
if (...)
  TEST_MACRO();
else 
{
    ...
}

宏展开后:
if (...) { \
if (A) \
  DO_A(); \
else \
  DO_B(); \
}

else 
{
  ...
}

 

扩展后第二个 else 前边多了一个分号,编译都不能通过,这其实是好的情况,因为你可以把问题扼杀在编译阶段,如果编译通过但是程序跑出奇怪的行为那才是痛苦。因此关于宏定义就有了do{} while(0)的使用方法 

1 #define TEST_MACRO() do{ \
2 if (true) \
3   DO_A(); \
4 else \
5   DO_B(); \
6 }while(0)

 

使用do{} while(0) 方法就是为了类似的宏可以在任何时候使用,总之宏定义正反作用都有并且在C++中是不推荐使用的(C++中建议用const定义常量、用inline定义函数),但是在C语言的项目中宏是大量存在的,不过程序终究是人写的,还是看人怎么去用它

posted on 2010-01-06 22:51  Simba Yang  阅读(1220)  评论(0编辑  收藏  举报