С++ включает/отключает отладочные сообщения 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;
}
Лучшие предложения всегда приветствуются.