日志在任何一种语言编程中都会涉及到,python中有logging库,java中有log4j。当然C也有日志功能,一般可以用宏和函数来实现。
需要明确下日志的功能,一般会设置一个日志等级,比如trace < debug < info < warn < error < fatal 等,根据设置的等级高低来判断是否显示日志。
1.宏实现
可以使用宏定义和条件编译来实现一个简单的日志函数,如下所示:
#include <stdio.h>
// 定义日志等级
#define LOG_LEVEL_DEBUG 0
#define LOG_LEVEL_INFO 1
#define LOG_LEVEL_WARN 2
#define LOG_LEVEL_ERROR 3
// 定义日志级别
#ifndef LOG_LEVEL
#define LOG_LEVEL LOG_LEVEL_INFO
#endif
// 定义日志函数
#define LOG(level, format, ...) \
do { \
if (level >= LOG_LEVEL) { \
printf("[%s] " format "\n", #level, ##__VA_ARGS__); \
} \
} while(0)
int main() {
int value = 42;
LOG(LOG_LEVEL_DEBUG, "Debug message, value = %d", value);
LOG(LOG_LEVEL_INFO, "Info message, value = %d", value);
LOG(LOG_LEVEL_WARN, "Warning message, value = %d", value);
LOG(LOG_LEVEL_ERROR, "Error message, value = %d", value);
return 0;
}
在这个例子中,我们定义了四个日志级别,并使用宏定义和条件编译来控制日志输出的级别。在main
函数中,我们使用LOG
宏输出不同级别的日志信息。
您可以根据您的需要修改LOG_LEVEL
的值来控制输出的日志级别。
这里##__VA_ARGS__
是一个预处理器的特殊标记,用于处理可变参数列表。这个标记的作用是将可变参数列表展开并与它前面的文本连接起来。通常,##VA_ARGS用于定义带有可变参数的宏。当宏被调用时,##VA_ARGS会将可变参数列表展开,并将展开后的参数直接与宏定义中的文本相连接。
2. 函数实现
我们创建一个名为log
的函数,函数接受日志级别和消息作为参数,并在函数内部根据日志级别输出相应的日志信息。以下是一个使用函数来实现日志功能的示例代码:
#include <stdio.h>
// 定义日志等级
typedef enum {
LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO,
LOG_LEVEL_WARN,
LOG_LEVEL_ERROR
} LogLevel;
// 定义日志函数
void log(LogLevel level, const char *format, ...) {
va_list args;
va_start(args, format);
if (level == LOG_LEVEL_DEBUG) {
printf("[DEBUG] ");
} else if (level == LOG_LEVEL_INFO) {
printf("[INFO] ");
} else if (level == LOG_LEVEL_WARN) {
printf("[WARN] ");
} else if (level == LOG_LEVEL_ERROR) {
printf("[ERROR] ");
}
vprintf(format, args);
printf("\n");
va_end(args);
}
int main() {
int value = 42;
log(LOG_LEVEL_DEBUG, "Debug message, value = %d", value);
log(LOG_LEVEL_INFO, "Info message, value = %d", value);
log(LOG_LEVEL_WARN, "Warning message, value = %d", value);
log(LOG_LEVEL_ERROR, "Error message, value = %d", value);
return 0;
}
在这个例子中,我们定义了一个枚举类型LogLevel
来表示不同的日志级别,然后创建了一个log
函数来处理日志输出。在main
函数中,我们使用log
函数输出不同级别的日志信息。
这种方法不使用宏,而是使用了函数来实现日志功能,使得日志功能更加灵活和易于维护。
值得注意的是:在这个函数声明中,"..."表示可变参数列表。这意味着函数可以接受任意数量的参数。在C语言中,可变参数列表通常使用stdarg.h中的宏来处理。在函数内部,可以使用这些宏来访问传递的可变参数。
另外,在C语言中,va_list、va_start和va_end是用于处理可变参数列表的宏和函数。
va_list: va_list是一个类型,用于声明一个指向参数列表的指针。它是一个指向参数列表的指针,可以用于遍历参数列表中的每个参数。
va_start: va_start宏用于初始化可变参数列表的遍历。它接受两个参数,第一个是一个va_list类型的变量,第二个是可变参数列表中的最后一个固定参数。va_start会将指向参数列表的指针指向第一个可变参数。
va_end: va_end宏用于结束可变参数列表的遍历。它接受一个参数,即va_list类型的变量。va_end会清理可变参数列表的状态,确保不会出现内存泄露。
使用这些宏和函数,可以在函数内部遍历可变参数列表,获取每个参数的值,并进行相应的处理。这在需要处理不定数量参数的函数中非常有用,比如printf函数就是一个典型的例子。