C++宏替换

例:

#define TEST_VAL 100

现在要将TEST_VAL转换成字符串使用:

#define TO_STR(x) #x

#define STR(x) TO_STR(x)

定义了上述两个宏之后在代码中这样使用

STR(TEST_VAL) 返回的便是字符串 “100”

 

为什么中间必须有一个过渡的宏TO_STR呢?宏被作为参数传入另一个宏时,预处理器会尝试将所有的宏替换成已经定义的字符串,但是如果宏的定义中带有 ## #这样的连接符,则参数宏不会被替换。

于是 STR(TEST_VAL) => TO_STR(100) => #100 => "100" 这个是因为STR的定义中不含有# ## ,而TEST_VAL在第一次替换时,便替换为了100

如果做一下定义:

#define STR2(x) #x

则 STR2(TEST_VAL) => #TEST_VAL => "TEST_VAL"

 

注:预处理器只会对宏进行简单的字符串替换。因此:

#define DBL(x) (x + x) , 该定义必须加上括号.

注:对于多行的宏建议使用do{}while(0) 的形式定义,比如

#define CALC(x) \

  do { \

    if (x > 0) \

      cout << "x > 0"; \

    else \

      cout << "x < 0"; \

  }while(0)

 

这样在使用宏的使用可以在尾部添加上分号,同时保证了宏定义的代码不会被外部干扰,也不会干扰外部。

使用do{}while(0)的目的就是为了添加上分号,而且很多编译器会能够将这种循环优化掉。

单单的使用{}则不能够在尾部添加分号。因为分号是多余的。

补充一个例子

#include <iostream>
#include <cmath>

#define CALC_O(x , y) \
    do {\
        int sum = (x) + (y); \
        std::cout << "sum = " << sum << std::endl; \
       } while(0)


int main(int argc , char** argv)
{
    if (int x = 3)
        CALC_O(x , 5);

    else
        CALC_O(6 , 7);

    return 0;
}

在上述例子中,如果不使用do--while封装,别的方案都容易出问题。

VC编译器和g++编译器在对##的处理是有有所区别的。举个例子

//! 这里使用Qt中的标识编译环境的宏

#ifdef Q_OS_MAC
#    define PLATFORM mac
#elif defined(Q_OS_WIN)
#    ifdef Q_OS_WIN64
#        define PLATFORM winx64
#    else
#        define PLATFORM winx86
#    endif
#else
#error "The platform is not supported!"
#endif

#ifdef __PROEDUCT_A__
#     define PRODUCT a
#else
#     define PRODUCT b
#endif

#define WEB_URL 

#define TO_STR(x) #x

#define CONNECT_STR TO_STR(PLATFORM ## PRODUCT)

#define PRODUCT_VERSION CONNECT_STR(PLATFORM , PRODUCT)

 

posted @ 2016-06-01 13:09  十月1993  阅读(1400)  评论(0编辑  收藏  举报