c - 在嵌入式 C 中使用 printf 进行多级调试

标签 c debugging macros embedded printf

我正在开发嵌入式系统,我使用 printf 在 UART 上创建日志。

我想创建一个调试源文件,我可以在其中设置所需的调试类型。

我定义了这个常量:

  • DEBUG_LOG_0 用于系统日志
  • DEBUG_LOG_1 用于系统调试
  • DEBUG_LOG_2 用于系统高级调试

从这个常量开始,我定义了这个宏来包装标准 printf:

    /* Define for debugging level 0 - System Logs */
#ifdef DEBUG_LEVEL_0
#define edi_Print_L0(...) printf(__VA_ARGS__)
#endif

#ifndef DEBUG_LEVEL_0
#define edi_Print_L0(...) printf(...)
#endif

/* Define for debugging level 1 - Debug */
#ifdef DEBUG_LEVEL_1
#define edi_Print_L0(...) printf(__VA_ARGS__)
#define edi_Print_L1(...) printf(__VA_ARGS__)
#endif

#ifndef DEBUG_LEVEL_1
#define edi_Print_L0(...) printf(...)
#define edi_Print_L1(...) printf(...)
#endif

/* Define for debugging level 2 - Advanced Debug */   
#ifdef DEBUG_LEVEL_2
#define edi_Print_L0(...) printf(__VA_ARGS__)
#define edi_Print_L1(...) printf(__VA_ARGS__)
#define edi_Print_L2(...) printf(__VA_ARGS__)
#endif

#ifndef DEBUG_LEVEL_2
#define edi_Print_L0(...) printf(...)
#define edi_Print_L1(...) printf(...)
#define edi_Print_L2(...) printf(...)
#endif

接下来,我将从头文件导入调试常量,以启用选定的调试级别。

关于宏定义有什么建议吗?有没有一种聪明的方法来实现我的目标?

谢谢!

最佳答案

在整个代码中传递日志级别/源,然后简单地在一个位置禁用/启用各个级别或源会更有意义。

即在您的代码中,您将使用:

Log(Log_Comm, LevelDebug, "Some minor stuff");
Log(Log_Comm, LevelWarn, "Something strange");
Log(Log_Comm, LevelError, "Something seriously wrong");
Log(Log_System, LevelDebug, "Some minor stuff");
Log(Log_System, LevelWarn, "Something strange");
Log(Log_System, LevelError, "Something seriously wrong");

然后你只需:

// log levels
#define LevelDebug 0x01
#define LevelInfo  0x02
#define LevelWarn  0x04
#define LevelError 0x08
#define LevelAll   0x0F

// enabled levels for individual log sources
#define Log_Comm    (LevelWarn | LevelError)
#define Log_System  (LevelAll)

#define Log(source, level, message) do { \
   if (source & level) { \
        sendToPort(message); \
   } \
} while (0)

(编辑)

正如 @Clifford 在评论中指出的,可能还需要全局禁用某个级别,而不必遍历所有源定义。这可以通过指定附加掩码来完成:

// if LevelDebug is omitted from this mask,
// debug message will not be logged regardless
// of individual source settings
#define Global_Level_Mask (LevelWarn | LevelError)

#define Log(source, level, message) do { \
    if (source & level & Global_Level_Mask) { \
       sendToPort(message); \
    } \
} while (0)

另一个问题可能是这将在您的代码周围产生许多“无法访问的代码”警告。我不确定如何在其他编译器中修复此问题,但是,例如在 Visual Studio 中,可以通过在 if 语句周围添加编译指示来解决此问题:

// visual studio will show a warning 
// C4127: "conditional expression is constant"
// when compiling with all warnings enabled (-w4)

// these pragmas will disable the warning around if's
#define Log(source, level, message) do { \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
    if (source & level & Global_Level_Mask) { \
__pragma(warning(pop)) \
        sendToPort(message); \
    } \
} while (0)

并不是它看起来有点难看,但恕我直言,它允许轻松使用和更多控制。

当然,没有什么可以阻止您为每个日志级别使用单独的宏(也许更简单,因为您少了一个参数),即:

#define LogDebug(source, message) Log(source, LevelDebug, message)
#define LogInfo(source, message) Log(source, LevelInfo, message)
#define LogWarn(source, message) Log(source, LevelWarn, message)

// usage example:
LogDebug(Log_Comm, "Some minor stuff");
LogWarn(Log_System, "Something strange");

关于c - 在嵌入式 C 中使用 printf 进行多级调试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37837904/

相关文章:

c - GtkTreeView同质列宽

c++ - 用于视频监控的 blobtracking 中的 cv_exports

java - 同时调试python和Java

c - #define的逻辑(microchip xc8编译器)

clojure - 需要完全限定符号的 Cljs 宏

c - 将 fmemopen ed 文件描述符设置为子进程的标准输入

debugging - 如何约束IntelliJ将调试源文件查找到当前模块?

ruby-on-rails - 如何像调试 Rails 应用程序一样调试 Sinatra 应用程序?

c++ - C++中的宏和常量有什么区别?

c - 尝试设置并打印指针的值