2009-08-20 2 views
4

Скажем, у меня есть функция C++ debugPrint (int foo). Как я могу лучше всего снять это с релизов? Я не хочу окружать каждый вызов debugPrint с помощью #ifdefs, поскольку это было бы очень трудоемким. С другой стороны, я хочу быть на 100% уверенным, что компилятор передает все вызовы этой функции, а сама функция - из сборки релиза. Зачистка также должна произойти, если она вызывается с параметром, результатом которого является вызов функции. Например, debugPrint (getFoo()) ;. В этом случае я также хочу, чтобы вызов getFoo() был удален. Я понимаю, что функция inlining может быть опцией, но поддержка не гарантируется.Как удалить код отладки во время компиляции в C++?

+1

Единственный способ избавиться от 'getFoo()' в 'DebugPrint (getFoo())' является использование макросов. Но это приведет к тому, что программа будет вести себя по-разному при отладке и в настройках выпуска. Это действительно опасно. –

+1

Это опасно, если getFoo() имеет некоторую скрытую логику, отличную от значения переменной foo. Но это плохое кодирование. – juvenis

ответ

13

Использование conditinal компиляции и макро:

#ifdef _DEBUG 
    #define LOG(x) debugPrint(x) 
#else 
    #define LOG(x) 
#endif 

Определение _DEBUG для отладочных и не определить его для построения релиза. Теперь в версии построить каждый

LOG(blahbhahblah); 

будет расширен в пустую строку - даже параметры не будут оценены и не будет включен в излучаемом код.

Вы можете использовать любой уже существующий символ препроцессора, который определен в сборке отладки и не определен в версии вместо _DEBUG.

+0

Yep .. это именно то, что есть для макросов !! – Newtopian

+6

Это опасно и подвержено ошибкам. 'int x = 0; LOG (x + = 2); use (x); 'будет вести себя иначе, если включен режим« release »или« отладка ». – LiraNuna

+2

Да, будет. В этом мире нет ничего свободного. – sharptooth

1

Я сделал что-то подобное раньше с препроцессором.

#ifndef DEBUG 
#define debugPrint 
#endif 

По существу, который удалит все отладочные строки

+1

Err, не будет ли это верным 'debugPrintf («hello»); в довольно недействительный "(" привет "); ? – paxdiablo

+1

@Pax, это совершенно верно. – strager

+1

Но это может вызвать предупреждение. '(void) (" hello ")' представляется более подходящим. Это неправильно: debugPrint (GetFoo()) по-прежнему вызывает GetFoo() с этим макросом, который явно не требовался. – MSalters

7

сделать функцию инлайн, и внутри функции имеют # IfDef, как и это:

inline void debugPrint(whatever_t wtvr) 
{ 
    #ifdef DEBUG 
     Logger::log(wtvr); 
    #endif 
} 

Таким образом, оптимизатор будет обирать пустую функцию, сохраняя код чистым.

+2

Будет ли это гарантировать, что параметр функции не будет оцениваться? – sharptooth

+0

Это не поможет с другим требованием (что если код, который необходимо оценить для вычисления wtvr, также не будет сгенерирован) –

+3

@sharptooth, они должны быть оценены с помощью этого решения. Однако, если оценка изменяет работу программы (то есть побочные эффекты), проблема в том, что вызовы функции регистратора могут делать больше, чем просто протоколирование. – strager

1

#ifdef _DEBUG 
#define debugPrint(x) _debugPrint(x) 
void _debugPrint(int foo) { 
    // debugPrint implementation 
} 
#else 
#define debugPrint(x) 
#endif 
2

@ ответ sharptooth хороший. Одно небольшое изменение, которое я обычно делаю, однако, чтобы отключить отладку, если NDEBUG макроса не определен, а не если отладочный макрос определяются:

#ifndef NDEBUG 
   #define LOG(x) debugPrint(x) 
#else 
   #define LOG(x) 
#endif 

Когда NDEBUG макроса определен, то C assert s, которые я предпочитаю использовать довольно либерально для утверждения таких вещей, как предпосылки и постусловия, или даже для разъяснения результата сложной логики, также отказаться от компиляции. Это стандартный макрос для «без отладки». И макрос NDEBUG уже должен быть определен в сборках релизов.

См: http://www.opengroup.org/onlinepubs/009695399/functions/assert.html

Смежные вопросы