目录
宏定义是比较常用的预处理指令,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏定义中替换列表中的内容。
宏定义有两种,不带参数的宏定义和带参数的宏定义。
不带参数的宏定义: #define 宏名 宏体
带参数的宏定义: #define 宏名(参数表) 宏体
其中参数表示多个参数采用‘,’隔开;还有一个有意思的设定就是,当宏体一行写不下时,可以使用反斜线\作为续行符延续到下一行,理论上这样就支持到无限复杂的替换内容。
设计前先了解几个基本概念,
【1】##用于将其左右两侧的操作符连接成一个操作符
【2】__VA_ARGS__表示该部分允许输入可变参数,这个是C99标准中的内容
【3】##__VA_ARGS__则是支持可变参数的输入或者无参数输入
OK,先假设我们采用的宏定义日志输出,共有多个日志等级,构建print函数类似于宏定义myprint.h如下:
- typedef enum PrintLevel
- {
- L_NOTICE = 1, //一般输出
- L_WARNING = 2, //告警输出
- L_TRACE = 3, //追踪调试
- L_DEBUG = 4, //软件bug
- L_FATAL = 5 //致命错误
- }PrintLevel;
-
- #define MyPrint(level,log_fmt,...) \
- do{ \
- switch(level) \
- { \
- case L_FATAL: \
- printf("L(5,FATAL)[%s:%d][%s] \n"log_fmt"\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
- break;\
- case L_DEBUG: \
- printf("L(4,DEBUG)[%s:%d][%s] \n"log_fmt"\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
- break;\
- case L_TRACE: \
- printf("L(3,TRACE)[%s:%d][%s] \n"log_fmt"\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
- break;\
- case L_WARNING: \
- printf("L(2,WARNING)[%s:%d][%s] \n"log_fmt"\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
- break;\
- case L_NOTICE: \
- printf("L(1,NOTICE)[%s:%d][%s] \n"log_fmt"\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
- break;\
- default: \
- printf("L(-1,UNKOWN)[%s:%d][%s] \n"log_fmt"\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
- break;\
- } \
- }while (0)
宏测试main.c代码如下
- #include
- #include
-
- #inlcude "myprint.h"
-
- int main(void){
- MyPrint(2,"my notice %d\n",1);
- system("pause");
- return 0;
- }