как разделить код режима отладки и выпуска - PullRequest
8 голосов
/ 24 марта 2010

В режиме отладки или во время тестирования мне нужно напечатать много различной информации, поэтому я использую этот метод:

#ifdef TESTING
// code with lots of debugging info
#else
// clean code only
#endif // TESTING`

Это хороший метод или есть какой-то другой простой и элегантный метод?

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

Спасибо.

Я использую MS Visual Studio.

Ответы [ 7 ]

17 голосов
/ 24 марта 2010

Вы можете использовать макрос для печати отладочной информации, а затем в сборке выпуска определить этот макрос как пустой.

например.,

#ifdef _DEBUG
#define DEBUG_PRINT(x) printf(x);
#else
#define DEBUG_PRINT(x)
#endif

Используя этот метод, вы также можете добавить дополнительную информацию, например

__LINE__ 
__FILE__

к отладочной информации автоматически.

6 голосов
/ 24 марта 2010

Написать один раз

#ifdef _DEBUG 
const bool is_debig = true;
#else 
const bool is_debig = false;
#endif 

, а затем

template<bool debug>
struct TemplateDebugHelper {
   void PrintDebugInfo(const char* );
   void CalcTime(...);
   void OutputInfoToFile(...);
   /// .....
};

// Empty inline specialization
template<>
struct TemplateDebugHelper<false> {
   void PrintDebugInfo(const char* ) {} // Empty body
   void CalcTime(...) {} // Empty body
   void OutputInfoToFile(...) {} // Empty body
   /// .....
};

typedef TemplateDebugHelper<is_debug> DebugHelper;

DebugHelper global_debug_helper;

int main() 
{
   global_debug_helper.PrintDebugInfo("Info"); // Works only for is_debug=true
}
2 голосов
/ 24 марта 2010

Используйте Log4Cxx вместо того, чтобы самому вести журнал. Пакет Log4Cxx легко настраивается, поддерживает различные уровни ведения журнала в зависимости от важности / серьезности и поддерживает несколько форм вывода.

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

2 голосов
/ 24 марта 2010

Используйте такое определение для заголовков include

#ifdef  TESTING
#define DEBUG_INFOS(_X_) CallYourDebugFunction(_X_ )
#else
#define DEBUG_INFOS(_X_) ((void)0)
#endif

и затем используйте только это в своем коде

...
DEBUG_INFOS("infos what ever");
RestOfWork();
...

Вы также можете использовать и искать макросы ASSERT и TRACE и использовать DebugView из sysinternals для чтения выходных данных в режиме реального времени из трассировки или трека проблемы с ASSERT. ASSERT и TRACE выполняют похожую работу, и вы можете получать от них идеи.

комментарии: я использую объявление TESTING, потому что вижу это по вопросу.

1 голос
/ 24 марта 2010

Вы можете использовать что-то вроде boost :: log , установив уровень серьезности на нужный вам.

void init()
{
    logging::core::get()->set_filter
    (
        flt::attr< logging::trivial::severity_level >("Severity") >= logging::trivial::info
    );
}

int main(int, char*[])
{
    init();

    BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
    BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
    BOOST_LOG_TRIVIAL(info) << "An informational severity message";
    BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
    BOOST_LOG_TRIVIAL(error) << "An error severity message";
    BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
}

Я думаю, у Пантеоса тоже есть что-то похожее.

0 голосов
/ 09 января 2014

Существует простой способ, который работает с большинством компиляторов:

#ifdef TESTING
    #define DPRINTF( args )     printf args
#else
    #define DPRINTF( args )     ((void)0)
#endif

Далее в исходном коде вы должны использовать его как:

DPRINTF(("Debug: value a = %d, value b = %d\n", a, b));

Недостатком является то, что вы должны использовать двойные скобки, но в старых C и C ++ Стандартные макросы не поддерживаются (только как расширение компилятора).

0 голосов
/ 24 марта 2010

Я пишу для встроенных систем на C. В своих программах я использую следующие макросы:

#define _L  log_stamp(__FILE__, __LINE__)

#define _LS(a)  log_string(a)

#define _LI(a)  log_long(a)

#define _LA(a,l)  log_array(a,l)

#define _LH(a)  log_hex(a)

#define _LC(a)  log_char(a)

#define ASSERT(con) log_assert(__FILE__, __LINE__, con)

Когда я делаю релизную версию, я просто отключаю директиву #define DEBUG, и все макросы становятся пустыми. Обратите внимание, что он не потребляет циклов процессора и памяти в версии выпуска. Макросы - это единственный способ сохранить информацию в журнале: где это было сделано (номер файла и строки).

Если мне нужна эта информация, я использую: _L;_LS("this is a log message number ");_LI(5);

в противном случае без директивы _L.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...