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)