目录
一、c语言的宏定义及宏替换特性
宏定义是比较常用的预处理指令,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏定义中替换列表中的内容。
宏定义有两种,不带参数的宏定义和带参数的宏定义。
不带参数的宏定义: #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 <stdio.h>
#include <stdlib.h>
#inlcude "myprint.h"
int main(void){
MyPrint(2,"my notice %d\n",1);
system("pause");
return 0;
}