#define的里里外外你知多少

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

  先看这个宏定义

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

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

  1 int a = MAX(2, 1) + 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语言的项目中宏是大量存在的,不过程序终究是人写的,还是看人怎么去用它

原文地址:https://www.cnblogs.com/linyawen/p/2479134.html