打开和关闭调试代码的方法

Vit*_*.us 4 c++ debugging

我正在编写一个针对arduino的manchester解码算法,我经常不得不在尝试工作时打印调试内容,但是打印到串口和字符串常量会增加很多开销.我不能把它留在最后的二进制文件中.

我通常只是通过代码删除任何调试相关的行.我正在寻找一种方法来轻松打开和关闭它.

我知道的唯一方法就是这个

 #if VERBOSE==1
     Serial.println();
     Serial.print(s);
     Serial.print(" ");
     Serial.print(t);
     Serial.print(" preamble");  
 #endif

...

 #if VERBOSE==1
     Serial.println(" SYNC!\n");
 #endif
Run Code Online (Sandbox Code Playgroud)

在我可以拥有的文件之上

#define VERBOSE 0 // 1 to debug
Run Code Online (Sandbox Code Playgroud)

我不喜欢它给单线增加了多少杂乱.我非常想做一些非常讨厌的事情.但是,邪恶.

将每个调试输出更改为

verbose("debug message");
Run Code Online (Sandbox Code Playgroud)

然后用

#define verbose(x) Serial.print(x) //debug on
Run Code Online (Sandbox Code Playgroud)

要么

#define verbose(x) //debug off
Run Code Online (Sandbox Code Playgroud)

有一个C++功能允许我这样做而不是预处理器吗?

5go*_*der 8

听起来很傻:是的,有一个C++功能,它看起来像这样:

if (DEBUG)
  {
     // Your debugging stuff here…
  }
Run Code Online (Sandbox Code Playgroud)

如果DEBUG是编译时常量(我认为使用宏是合理的,但在这种情况下不需要),如果debug编译时为false,编译器几乎肯定不会为调试内容生成任何代码(甚至不是分支).

在我的代码中,我喜欢有几个调试级别.然后我可以这样写:

if (DEBUG_LEVEL >= DEBUG_LEVEL_FINE)
  {
     // Your debugging stuff here…
  }
Run Code Online (Sandbox Code Playgroud)

同样,如果条件在编译时为假,编译器将优化掉整个构造.

通过允许双倍调试级别,您甚至可以获得更多的幻想.在编译时启用的最大级别以及在运行时使用的实际级别.

if (MAX_DEBUG >= DEBUG_LEVEL_FINE && Config.getDebugLevel() >= DEBUG_LEVEL_FINE)
  {
     // Your debugging stuff here…
  }
Run Code Online (Sandbox Code Playgroud)

您可以#define MAX_DEBUG达到希望在运行时选择的最高级别.在全性能构建中,您可以#define MAX_DEBUG 0使条件始终为false并且根本不生成任何代码.(当然,在这种情况下,您无法在运行时选择调试.)

但是,如果挤出最后一条指令不是最重要的问题而且所有调试代码都是一些日志记录,那么通常的模式就像这样:

class Logger
{
public:

  enum class LoggingLevel { ERROR, WARNING, INFO, … };

  void logError(const std::string&) const;
  void logWarning(const std::string&) const;
  void logInfo(const std::string&) const;
  // …

private:

  LoggingLevel level_;
};
Run Code Online (Sandbox Code Playgroud)

然后,各种函数将当前日志记录级别与函数名称指示的级别进行比较,如果较小,则立即返回.除紧环外,这可能是最方便的解决方案.

最后,我们可以通过为班级提供inline包装来结合两个世界Logger.

class Logger
{
public:

  enum class LoggingLevel { ERROR, WARNING, INFO, … };

  void
  logError(const char *const msg) const
  {
    if (COMPILE_TIME_LOGGING_LEVEL >= LoggingLevel::ERROR)
      this->log_(LoggingLevel::ERROR, msg);
  }

  void
  logError(const std::string& msg) const
  {
    if (COMPILE_TIME_LOGGING_LEVEL >= LoggingLevel::ERROR)
      this->log_(LoggingLevel::ERROR, msg.c_str());
  }

  // …

private:

  LoggingLevel level_;

  void
  log_(LoggingLevel, const char *) const;
};
Run Code Online (Sandbox Code Playgroud)

只要评估Logger::logError等调用的函数参数没有可见的副作用,如果inline函数中的条件为假,编译器将消除调用的可能性很大.这就是为什么我添加了带有原始C字符串的重载,以优化使用字符串文字调用函数的常见情况.看看装配是否确定.