在C++项目工程中,经常可以看见各式各样的宏定义。宏定义主要是为了方便扩展以及简化代码量,而在我们自己编写的宏定义以外,编译器也提供了一些默认宏定义。
1. 文件相关
__LINE__:获取当前代码所在行数。
__FILE__:获取当前文件名。
__func__:获取当前代码所在的函数名称。如果该函数为类成员函数,同时想获取类名的话,可以通过__PRETTY_FUNCTION__宏取得完整信息,然后自行拆解。
2. 字符串相关
#:将其后的元素用双引号包含,如#A,其展开后即为"A"。
##:将前后两个元素进行拼接,如A##B,展开后即为AB。
3. 可变参数
__VA_ARGS__:如果宏定义参数个数不确定,类似于printf函数的参数列表,则可使用该宏定义表达。
4. 代码示例
#include <stdio.h>
#define Print1(Number) printf("[Print1]value = %d\n",test##Number)
#define Print2(Name, format, ...) printf("[Print2]" #Name " value: " #format "\n", ##__VA_ARGS__)
// __VA_ARGS__前加##的作用是当可变参数个数为0时,去除前面的','避免编译报错
#define Print3() printf("[Print3]Line:%d\n File:%s\n Func:%s\n Pretty_Func:%s\n", __LINE__, __FILE__, __func__, __PRETTY_FUNCTION__)
class MainCls{
public:
void main() {
Print3();
}
};
int main(void)
{
int test12 = 3;
Print1(12);
int group[] = {1, 2};
Print2(group, "%d %d", group[0], group[1]);
MainCls tmp;
tmp.main();
return 0;
}
输出结果如下所示:
这篇博文:C++宏定义中后半段对宏定义的各种情况做了详细描述,如果各位小伙伴们对此感兴趣可以移步阅读。
5. 条件编译
在一些情况下,合理利用宏定义与条件编译可以达到较高的代码适配水平(另外auto自动推断也有较好的适配性),在编译层面就已经确立了实际要执行的逻辑代码。
#if, #elif, #else, #endif:使用逻辑判断对应的代码段是否需要编译进目标文件中。
#ifdef, #else, #endif:同上,但使用宏定义是否存在进行判断。
__if_exists, __if_not_exists:使用标识符是否存在进行判断(c++11或以上支持)。标识符可以是变量名也可以是函数名,但无法区分重载函数。
具体使用样例如下所示:
#if macro_name > 3
// todo
#endif // macro_name > 3
#ifdef macro_name
// todo
#endif // macro_name
__if_exists ( var_name ) {
// todo
};