1.debug.c
cpp
// dbg.h
#pragma once
#include <stdio.h>
// 日志级别枚举
typedef enum {
DBG_NONE = 0,
DBG_ERROR = 1,
DBG_WARN = 2,
DBG_INFO = 3,
DBG_DEBUG = 4,
DBG_TRACE = 5
} dbg_level_t;
// 全局日志级别(外部定义)
extern int g_dbg_level;
// 带级别的调试宏(使用全局变量)
#define dbg_log(level, fmt, ...) \
do { \
if (level <= g_dbg_level) { \
const char *level_str[] = { \
"NONE", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" \
}; \
fprintf(stderr, "[%s] %s:%d:%s(): " fmt, \
level_str[level], __FILE__, __LINE__, \
__func__, ##__VA_ARGS__); \
} \
} while(0)
// 快捷宏
#define dbg_error(fmt, ...) dbg_log(DBG_ERROR, fmt, ##__VA_ARGS__)
#define dbg_warn(fmt, ...) dbg_log(DBG_WARN, fmt, ##__VA_ARGS__)
#define dbg_info(fmt, ...) dbg_log(DBG_INFO, fmt, ##__VA_ARGS__)
#define dbg_debug(fmt, ...) dbg_log(DBG_DEBUG, fmt, ##__VA_ARGS__)
#define dbg_trace(fmt, ...) dbg_log(DBG_TRACE, fmt, ##__VA_ARGS__)
2.load_config.c
cpp
// config_loader.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// 日志级别枚举
typedef enum {
DBG_NONE = 0,
DBG_ERROR = 1,
DBG_WARN = 2,
DBG_INFO = 3,
DBG_DEBUG = 4,
DBG_TRACE = 5
} dbg_level_t;
// 全局日志级别变量
extern int g_dbg_level;
// 配置文件名
#define CONFIG_FILE "config.ini"
// 从字符串转换为日志级别
static dbg_level_t string_to_level(const char *str) {
if (str == NULL) return DBG_INFO;
if (strcasecmp(str, "NONE") == 0) return DBG_NONE;
if (strcasecmp(str, "ERROR") == 0) return DBG_ERROR;
if (strcasecmp(str, "WARN") == 0) return DBG_WARN;
if (strcasecmp(str, "INFO") == 0) return DBG_INFO;
if (strcasecmp(str, "DEBUG") == 0) return DBG_DEBUG;
if (strcasecmp(str, "TRACE") == 0) return DBG_TRACE;
// 也支持数字
int num = atoi(str);
if (num >= 0 && num <= 5) return num;
return DBG_INFO; // 默认值
}
// 读取配置文件
void load_config() {
FILE *file = fopen(CONFIG_FILE, "r");
if (!file) {
printf("无法打开配置文件 %s,使用默认设置\n", CONFIG_FILE);
g_dbg_level = DBG_INFO;
return;
}
char line[256];
char section[64] = "";
while (fgets(line, sizeof(line), file)) {
// 去掉换行符
line[strcspn(line, "\n")] = 0;
// 去掉首尾空格
char *p = line;
while (isspace(*p)) p++;
char *end = p + strlen(p) - 1;
while (end > p && isspace(*end)) *end-- = 0;
// 空行或注释
if (*p == 0 || *p == '#' || *p == ';') continue;
// 检查是否是节
if (p[0] == '[' && strchr(p, ']')) {
char *close_bracket = strchr(p, ']');
*close_bracket = 0;
strncpy(section, p + 1, sizeof(section) - 1);
continue;
}
// 解析键值对
char *equal = strchr(p, '=');
if (!equal) continue;
*equal = 0;
char *key = p;
char *value = equal + 1;
// 去掉键和值的空格
while (isspace(*key)) key++;
char *key_end = key + strlen(key) - 1;
while (key_end > key && isspace(*key_end)) *key_end-- = 0;
while (isspace(*value)) value++;
char *value_end = value + strlen(value) - 1;
while (value_end > value && isspace(*value_end)) *value_end-- = 0;
// 如果是日志配置
if (strcmp(section, "logging") == 0) {
if (strcasecmp(key, "level") == 0) {
g_dbg_level = string_to_level(value);
printf("从配置文件设置日志级别: %s (%d)\n", value, g_dbg_level);
}
}
}
fclose(file);
}
// 更新日志级别(可用于动态调整)
void set_log_level(dbg_level_t level) {
g_dbg_level = level;
printf("日志级别已更改为: %d\n", level);
}
3.main.c
cpp
// main.c
#include "dbg.h"
#include "config_loader.h"
// 定义全局变量
int g_dbg_level = DBG_INFO; // 默认值
int main() {
// 1. 加载配置
load_config();
// 2. 测试各种日志级别
dbg_error("这是一个错误消息\n");
dbg_warn("这是一个警告消息\n");
dbg_info("这是一个信息消息\n");
dbg_debug("这是一个调试消息\n");
dbg_trace("这是一个跟踪消息\n");
// 3. 动态调整级别
printf("\n动态调整日志级别为DEBUG...\n");
set_log_level(DBG_DEBUG);
dbg_error("错误消息仍然显示\n");
dbg_debug("现在调试消息也会显示了!\n");
return 0;
}
4.添加颜色
cpp
// main.c
#include "dbg.h"
#include "config_loader.h"
// 定义全局变量
int g_dbg_level = DBG_INFO; // 默认值
int main() {
// 1. 加载配置
load_config();
// 2. 测试各种日志级别
dbg_error("这是一个错误消息\n");
dbg_warn("这是一个警告消息\n");
dbg_info("这是一个信息消息\n");
dbg_debug("这是一个调试消息\n");
dbg_trace("这是一个跟踪消息\n");
// 3. 动态调整级别
printf("\n动态调整日志级别为DEBUG...\n");
set_log_level(DBG_DEBUG);
dbg_error("错误消息仍然显示\n");
dbg_debug("现在调试消息也会显示了!\n");
return 0;
}