【问题标题】:C++ enable/disable debug messages of std::couts on the flyC++ 即时启用/禁用 std::couts 的调试消息
【发布时间】:2011-03-23 05:47:42
【问题描述】:

有没有办法在程序内部使用 std::cout 定义/取消定义调试消息?

我知道有诸如#define、#ifndef 之类的东西,但我在想有没有更简洁的方法来让变量说:

# debug ON

打印我所有的调试数据(使用 std::cout)。因此,我们将有这样的代码进行调试:

#ifndef DEBUG
// do something useful
#endif

当您编写 100 段调试代码时,我发现上面的代码很麻烦。

谢谢!

卡洛

【问题讨论】:

    标签: c++ debugging


    【解决方案1】:
    #ifdef DEBUG
    #define DEBUG_MSG(str) do { std::cout << str << std::endl; } while( false )
    #else
    #define DEBUG_MSG(str) do { } while ( false )
    #endif
    
    int main()
    {
        DEBUG_MSG("Hello" << ' ' << "World!" << 1 );
        return 0;
    }
    

    【讨论】:

    • 这不是您可以在运行时更改的内容。如果“即时”是指在编译时,那么这是满足您需求的一个非常简单且很好的答案。如果您需要在运行时更改它,日志库旨在执行此操作,并且可以通过某些文件而不是编译时标志进行配置。
    • @SB 我理解“on the fly”是指编译时,因为他使用#ifndef debug
    • do while 这里的目的是什么?
    • @cYrus 强迫你放一个';'在宏调用结束时每次。确保: if (c) MACRO(param) \ func(other);不会变成 if (c) func(other);当宏扩展为“空”文本时(即没有“;”
    • 而不是do { } while (false) 为什么不放一个0,例如,作为原子操作0;?
    【解决方案2】:

    除非您有复杂的日志记录需求,否则某些日志记录库的重量会很大。这是我刚刚拼凑起来的东西。需要进行一些测试,但可能会满足您的要求:

    #include <cstdio>
    #include <cstdarg>
    
    class CLog
    {
    public:
        enum { All=0, Debug, Info, Warning, Error, Fatal, None };
        static void Write(int nLevel, const char *szFormat, ...);
        static void SetLevel(int nLevel);
    
    protected:
        static void CheckInit();
        static void Init();
    
    private:
        CLog();
        static bool m_bInitialised;
        static int  m_nLevel;
    };
    
    bool CLog::m_bInitialised;
    int  CLog::m_nLevel;
    
    void CLog::Write(int nLevel, const char *szFormat, ...)
    {
        CheckInit();
        if (nLevel >= m_nLevel)
        {
            va_list args;
            va_start(args, szFormat);
            vprintf(szFormat, args);
            va_end(args);
        }
    }
    void CLog::SetLevel(int nLevel)
    {
        m_nLevel = nLevel;
        m_bInitialised = true;
    }
    void CLog::CheckInit()
    {
        if (!m_bInitialised)
        {
            Init();
        }
    }
    void CLog::Init()
    {
        int nDfltLevel(CLog::All);
        // Retrieve your level from an environment variable, 
        // registry entry or wherecer
        SetLevel(nDfltLevel);
    }
    
    int main()
    {
        CLog::Write(CLog::Debug, "testing 1 2 3");
        return 0;
    }
    

    【讨论】:

    • 谢谢!我会调查一下。这看起来很适合我的小程序!
    • 不做任何锁定。如果你的程序是多线程的,你可能需要它。
    【解决方案3】:

    可能不会。我建议使用日志库。我不确定 C++ 的最佳选择是什么,但我过去使用过 log4cpp,发现它非常好。

    编辑:我假设动态意味着@运行时。如果您只需要它作为编译时标志,那么Gianni's answer 可能最容易实现。日志库为您提供了很大的灵活性,并且允许在运行时重新配置。

    【讨论】:

    • +1。 log4cpp 有点老了;我建议调查 log4cxx,Boost.Log 候选者之一或 Pantheios。
    • @Carlo - 您可能想查看 Josh 建议的那些。我知道 log4cpp 有点老了。
    【解决方案4】:

    另一个简单的解决方案是在调试模式下打开std::ostreamcout 的引用,在非调试模式下打开/dev/null 引用,如下所示:

    在 debug.h 中:

    extern std::ostream &dout;
    

    在 debug.c 中

    #ifdef DEBUG
    std::ostream &dout = cout;
    #else
    std::ofstream dev_null("/dev/null");
    std::ostream &dout = dev_null;
    #endif
    

    然后:

    dout << "This is a debugging message";
    

    当然,这仅适用于/dev/null 指向空设备的任何系统。因为dout 引用在这里是全局的,所以它很像cout。这样,您可以将同一个流指向多个输出流,例如指向一个日志文件,具体取决于调试标志的值等。

    【讨论】:

    • 这个答案很有趣,但我不得不问如何在 Windows 上实现它。
    【解决方案5】:

    虽然这个问题很老,并且有一些很好的答案,但我也想发布一个解决方案。这就像扬尼斯的方法,但不同。而且,我使用了 std::cerr 而不是 std::cout,但你可以很快地改变它。

    #include <iostream>
    #ifdef DEBUG
    #  define DEBUG_LOG std::cerr
    
    #else
    class log_disabled_output {};
    static log_disabled_output log_disabled_output_instance;
    
    template<typename T>
    log_disabled_output& operator << (log_disabled_output& any, T const& thing) { return any; }
    
    // std::endl simple, quick and dirty
    log_disabled_output& operator << (log_disabled_output& any, std::ostream&(*)(std::ostream&)) { return any; }
    
    #  define DEBUG_LOG log_disabled_output_instance 
    #endif
    
    int main() {
        int x=0x12345678;
        DEBUG_LOG << "my message " << x << " " << "\n more information" << std::endl;
    };
    

    现在您可以像使用输出流一样使用它了。

    (注意:iostream 仅在使用 cerr 时才包含。如果您还没有包含它,这将减少包含的数量。 - 编辑:不适用于 @987654324 @支持)。
    如果DEBUG 被定义cerr 用于打印错误。否则,虚拟类log_disabled_output 被静态实例化,operator&lt;&lt; 被重载为任何类型。优势是;如果您禁用日志记录,聪明的编译器会注意到与流无关并优化整个“行”,因此如果禁用DEBUG,您不会有任何开销。

    【讨论】:

    • 我不能在这个 DEBUG_LOG 中使用endl,不是吗?
    • @ephemerr:不是以前的版本,而是额外的重载。请看我的编辑。请注意,这只是一个指向方向的示例,而不是实际的完整实现。不过,如果需要,您可以扩展它。
    【解决方案6】:

    我试图做同样的事情。经过一些研究,我开发了以下内容,它似乎有效。如果您发现任何错误,请发表评论。

    ostream DbgMsg(NULL);
    enum {
      DBGMSG_NONE,
      DBGMSG_DEFAULT,
      DBGMSG_VERBOSE
    } DbgLvl = DBGMSG_DEFAULT;
    
    ostream &DbgMsgDefault(ostream &stream) {
      return (DbgLvl>=DBGMSG_DEFAULT) ? cout : stream;
    }
    
    ostream &DbgMsgVerbose(ostream &stream) {
      return (DbgLvl>=DBGMSG_VERBOSE) ? cout : stream;
    }
    
    void main() {
       DbgMsg<<DbgMsgDefault<<"default:default"<<endl;
       DbgMsg<<DbgMsgVerbose<<"default:verbose"<<endl;
       DbgLvl = DBGMSG_NONE;
       DbgMsg<<DbgMsgDefault<<"none:default"<<endl;
    }
    

    【讨论】:

    • 欢迎来到 Stack Overflow!您是否会考虑添加一些叙述来解释为什么此代码有效,以及是什么使它成为问题的答案?这对提出问题的人以及其他任何出现的人都非常有帮助。
    【解决方案7】:

    一个干净的做法是使用 cerr。

    “cerr”本质上相当于“cout”,但总是刷新输出(顺便说一下,对调试很有用)。如果您需要删除所有消息,您可以通过简单的查找和替换(cerr into //cerr)将所有 cerr 消息注释掉。

    可能有更好的方法来使用 cerr 并彻底停用它(它写入一个特殊的流,即错误流,因此得名)。 我希望这会有所帮助。

    【讨论】:

      【解决方案8】:

      这是我使用的(使用 VC++)——这里“##”用于连接

      #ifdef DEBUG 
      #define pout cout 
      #else
      #define pout / ## / cout 
      #endif 
      

      对于其他编译器使用这个:

      #ifdef DEBUG 
      #define pout cout 
      #else
      #define pout 0 && cout 
      #endif 
      

      用法:

      pout << "hello world" << endl; 
      

      【讨论】:

      • 虽然这可能是一个不错的 hack,但我宁愿不使用它。请记住,多行 cout 的每一行都必须以 pout 开头,并且在预处理后考虑如下内容: if (condition) LF //conditional_command(); LF unconditional_command();
      【解决方案9】:

      我正在寻找类似的示例并在下面分享我的示例:

      #include <iostream>
      enum debug_option
      {
          DEBUG_DISABLE,
          DEBUG_ENABLE
      };
      
      class debug
      {
      public:
          debug_option debug_state;
      
          debug() : debug_state(DEBUG_ENABLE) {} // constr
          debug(debug_option state) : debug_state(state) {} // constr
      
          template<typename T>
          debug & operator<< (T input)
          {
          if (this->debug_state == DEBUG_ENABLE)
              std::cout << input;
          return *this;
          }
      };
      
      int main()
      {
          debug log, log_lev2(DEBUG_DISABLE);
          log << "print 1..\n" << 55 << " over\n";
          log.debug_state = DEBUG_DISABLE;
          log << "print 2..\n" << 3 << "over\n";
          log_lev2 << "print 3..\n" << 4 << "over\n";
          log_lev2.debug_state = DEBUG_ENABLE;
          log_lev2 << "print 5..\n";
          std::cout << "std::cout << print..\n";
          return 0;
      }
      

      我们随时欢迎更好的建议。

      【讨论】:

        猜你喜欢
        • 2016-01-11
        • 1970-01-01
        • 1970-01-01
        • 2011-07-15
        • 1970-01-01
        • 1970-01-01
        • 2022-01-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多