宏替换
#define 定义宏替换,#define 之后的宏都将被替换为宏的定义,直到用 #undef 解除该宏的定义。宏定义分为不带参数的常量宏(Object-like macros)和带参数的函数宏(Function-like macros)。其格式如下:
#define identifier replacement-list (1)
#define identifier( parameters ) replacement-list (2)
#define identifier( parameters, … ) replacement-list (3) (since C++11)
#define identifier( … ) replacement-list (4) (since C++11)
#undef identifier (5)
对于有参数的函数宏,在replacement-list中,"#"置于identifier面前表示将identifier变成字符串字面值,"##"连接,下面的例子来自cppreference.com:
#include <iostream>
//make function factory and use it
#define FUNCTION(name, a) int fun_##name() { return a;}
FUNCTION(abcd, 12);
FUNCTION(fff, 2);
FUNCTION(kkk, 23);
#undef FUNCTION
#define FUNCTION 34
#define OUTPUT(a) std::cout 《 #a 《 '\n'
int main()
{
std::cout 《 "abcd: " 《 fun_abcd() 《 '\n';
std::cout 《 "fff: " 《 fun_fff() 《 '\n';
std::cout 《 "kkk: " 《 fun_kkk() 《 '\n';
std::cout 《 FUNCTION 《 '\n';
OUTPUT(million); //note the lack of quotes
std::cin.get();
return 0;
}
可变参数宏是C++11新增部分(来自C99),使用时用__VA_ARGS__指代参数"…",一个摘自C++标准2011的例子如下(标准举的例子就是不一样啊):
#define debug(…) fprintf(stderr, __VA_ARGS__)
#define showlist(…) puts(#__VA_ARGS__)
#define report(test, …) ((test) puts(#test) : printf(__VA_ARGS__))
debug("Flag");
debug("X = %d\n", x);
showlist(The first, second, and third items.);
report(x>y, "x is %d but y is %d", x, y);
这段代码在预处理后产生如下代码:
fprintf(stderr, "Flag");
fprintf(stderr, "X = %d\n", x);
puts("The first, second, and third items.");
((x>y) puts("x>y") : printf("x is %d but y is %d", x, y));
在上面条件编译就讲到,有时用 #ifdef macro_NAME 来识别一些信息,C++标准指定了一些预定义宏,列在下表中(C++11新增宏已标出):
Predefined macros
Meaning
Remark
__cplusplus
在C++98中定义为199711L,C++11中定义为201103L
__LINE__
指示所在的源代码行数(从1开始),十进制常数
__FILE__
指示源文件名,字符串字面值
__DATE__
处理时的日期,字符串字面值,格式"Mmm dd yyyy"
__TIME__
处理时的时刻,字符串字面值,格式"hh:mm:ss"
__STDC__
指示是否符合Standard C,可能不被定义
wikipedia条目
__STDC_HOSTED__
若是Hosted Implementation,定义为1,否则为0
C++11
__STDC_MB_MIGHT_NEQ_WC__
见ISO/IEC 14882:2011
C++11
__STDC_VERSION__
见ISO/IEC 14882:2011
C++11
__STDC_ISO_10646__
见ISO/IEC 14882:2011
C++11
__STDCPP_STRICT_POINTER_SAFETY__
见ISO/IEC 14882:2011
C++11
__STDCPP_THREADS__
见ISO/IEC 14882:2011
C++11
其中上面5个宏一定会被定义,下面从__STDC__开始的宏不一定被定义,这些预定义宏不能被 #undef.使用这些宏的一个例子如下(连续字符串字面值会被自动相连,"ab""cde" 等价于 "abcde"):
1 #include <iostream>
2 int main()
3 {
4 #define PRINT(arg) std::cout 《 #arg": " 《 arg 《 '\n'
5 PRINT(__cplusplus);
6 PRINT(__LINE__);
7 PRINT(__FILE__);
8 PRINT(__DATE__);
9 PRINT(__TIME__);
10 #ifdef __STDC__
11 PRINT(__STDC__);
12 #endif
13 std::cin.get();
14 return 0;
15 }
这些宏经常用于输出调试信息。预定义宏一般以"__"作为前缀,所以用户自定义宏应该避开"__"开头。
应当指出的是,现代的C++程序设计原则不推荐适用宏定义常量或函数宏,应该尽量少的使用 #define ,如果可能,用 const 变量或 inline 函数代替。
重定义行号和文件名
从 #line number ["filename"] 的下一行源代码开始, __LINE__ 被重定义为从 number 开始,__FILE__ 被重定义"filename"(可选),一个例子如下:
1 #include <iostream>
2 int main()
3 {
4 #define PRINT(arg) std::cout 《 #arg": " 《 arg 《 '\n'
5 #line 999 "WO"
6
7 PRINT(__LINE__);
8 PRINT(__FILE__);
9 std::cin.get();
10 return 0;
11 }