С++ включает/отключает отладочные сообщения std:: couts на лету

Есть ли способ определить /undefine отладочные сообщения, используя std:: cout, когда внутри программы?

Я знаю, что есть такие вещи, как #define, #ifndef, но я думал, есть ли более чистый способ иметь переменную say:

# debug ON

Это печатает все мои данные отладки (используя std:: cout). Следовательно, для отладки у нас будет такой код:

#ifndef DEBUG
// do something useful
#endif

Я считаю, что приведенный выше код громоздкий, когда вы пишете 100-секундный код отладки.

Спасибо!

Carlo

Ответы

Ответ 1

Некоторые библиотеки протоколирования имеют довольно большой вес, если у вас нет сложных запросов на ведение журнала. Здесь что-то я только что сбил. Требуется небольшое тестирование, но может удовлетворить ваши требования:

#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;
}

Ответ 2

#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;
}

Ответ 3

Наверное, нет. Я бы рекомендовал использовать библиотеку протоколирования. Я не уверен, что лучший вариант для С++ больше, но я использовал log4cpp в прошлом и нашел его довольно хорошим.

EDIT: Я предполагаю, что на лету означает @runtime. Если вам просто нужно, чтобы это был флаг времени компиляции, тогда ответ Джанни, вероятно, проще всего реализовать. Журнальные библиотеки предоставляют вам большую гибкость и позволяют реконфигурировать @runtime.

Ответ 4

Хотя вопрос старый, и есть несколько хороших ответов, я хочу опубликовать и решение этой проблемы. Это как подход Джанниса, но другой. Кроме того, я использовал 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. Это уменьшит количество включений, если оно еще не включено. -edit: не с поддержкой std::endl).
Если DEBUG определен, для вывода ошибки используется cerr. В противном случае фиктивный класс log_disabled_output статически, а operator<< перегружается на любой тип. Преимущество есть; Если вы отключите ведение журнала, умный компилятор заметит, что с потоком ничего не нужно делать, и оптимизирует всю "линию", поэтому у вас не будет никаких накладных расходов, если DEBUG отключен.

Ответ 5

Я пытался сделать то же самое. После некоторых исследований я разработал следующее, и, похоже, он работает. Прошу прокомментировать, если вы видите что-то не так.

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;
}

Ответ 6

Еще одно простое решение включает открытие ссылки std::ostream на cout в режиме отладки и /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. Таким образом, вы можете указать один и тот же поток на несколько выходных потоков, например, на файл журнала, в зависимости от значения флагов отладки и т.д.

Ответ 7

Чистая вещь, которую нужно сделать, - использовать cerr.

"cerr" действует по существу как "cout", но всегда сбрасывает вывод (полезный для отладки, кстати). Если вам нужно удалить все сообщения, вы можете прокомментировать все сообщения cerr с помощью простой find-and-replace (cerr в //cerr ).

Есть, вероятно, еще лучшие способы использования cerr и деактивация его чисто (который записывает в специальный поток, поток ошибок, отсюда и название). Надеюсь, это поможет.

Ответ 8

Это то, что я использовал (работал с VС++) - здесь "##" используется для concatennation

#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; 

Ответ 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;
}

Лучшие предложения всегда приветствуются.