SRC: макрос для DEBUG
От: Кодт Россия  
Дата: 13.11.02 09:24
Оценка: 121 (12)
В тех случаях, когда в отладочной версии не хватает стандартных инструментов (TRACE/ATLTRACE, assert/ASSERT/ATLASSERT), приходится писать блоки кода в обрамлении
#ifdef _DEBUG
...
#endif

что не добавляет красоты, но потенциально плодит ошибки (компилятору абсолютно пофиг, где стоит #endif).

Макросы IS_DEBUG и DEBUG_ONLY позволяют свести эти изыски к синтаксису языка Си.
// IS_DEBUG - булева константа, истинна если собирается DEBUG-версия

#ifndef IS_DEBUG

  #if defined(DEBUG) || defined(_DEBUG) // проверяем оба признака
    #define IS_DEBUG true
  #else
    #define IS_DEBUG false
  #endif

#endif

// DEBUG_ONLY - префикс оператора, который выполнится только в DEBUG-версии
// синтаксис - аналогичен составному оператору while()

#ifndef DEBUG_ONLY

  #define DEBUG_ONLY if(!(IS_DEBUG)) {} else
  // такая конструкция нужна, чтобы не конфликтовать с внешним if

#endif

// аналогично ему - RELEASE_ONLY
// хотя зачем он может пригодиться - не знаю; пусть будет.

#ifndef RELEASE_ONLY

  #define RELEASE_ONLY if(IS_DEBUG) {} else

#endif


Пример использования
  // одиночный оператор
  DEBUG_ONLY fprintf(log, "Контрольная точка 1.\n");

  // составной оператор
  DEBUG_ONLY
  {
    FILE* log = fopen("c:/log.txt", "a");
    fprintf(log, "Контрольная точка 2.\n");
    fclose(log);
  }

  // использование в выражениях
  printf("Вас приветствует CoolApp (ver.1.2.%s)\n", IS_DEBUG ? "beta" : "rc1");
  int i = (!IS_DEBUG) * rand(); // в дебаге - всегда 0, в релизе - случайное число
Перекуём баги на фичи!
Re: SRC: макрос для DEBUG
От: McSeem2 США http://www.antigrain.com
Дата: 14.11.02 01:50
Оценка:
Здравствуйте Кодт, Вы писали:

К>В тех случаях, когда в отладочной версии не хватает стандартных инструментов...


Что-то мне это не нравится с одной стороны. С другой стороны — красиво. Не нравится тем, что при использовании DEBUG_ONLY в release версии все равно будет присутствовать мертвый код, и будет jmp для его обхода — и не надо надеяться на оптимизатор! К тому же, будут дополнительные предупреждения компилятора типа "code can never be reached" — я не говорю о MS C++, я говорю о грамотных C++ компиляторах вообще. В общем, у меня противоречивое мнение — "элегантно, но грязно"

McSeem
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[2]: SRC: макрос для DEBUG
От: Кодт Россия  
Дата: 14.11.02 09:50
Оценка:
Здравствуйте McSeem2, Вы писали:

MS>Что-то мне это не нравится с одной стороны. С другой стороны — красиво. Не нравится тем, что при использовании DEBUG_ONLY в release версии все равно будет присутствовать мертвый код, и будет jmp для его обхода — и не надо надеяться на оптимизатор!


Почему?

MS>К тому же, будут дополнительные предупреждения компилятора типа "code can never be reached" — я не говорю о MS C++, я говорю о грамотных C++ компиляторах вообще. В общем, у меня противоречивое мнение — "элегантно, но грязно"


В финальном релизе можно повыкидывать код.
Например, определить макросы
#define BEGIN_DEBUG  DEBUG_ONLY {
#define END_DEBUG    }

...
BEGIN_DEBUG
  fprintf(log, "hello,bugs!");
END_DEBUG

а перед выпуском версии повыдирать фрагменты BEGIN_DEBUG — END_DEBUG.

К сожалению, С++ не позволяет делать мета-макросы, вида
#define BEGIN_DEBUG  { #ifdef DEBUG
#define END_DEBUG    #endif }

(хотя, может быть, в C99 уже есть что-то такое?)
Перекуём баги на фичи!
Re[3]: SRC: макрос для DEBUG
От: McSeem2 США http://www.antigrain.com
Дата: 14.11.02 17:22
Оценка:
Здравствуйте Кодт, Вы писали:

К>Здравствуйте McSeem2, Вы писали:


MS>>Что-то мне это не нравится с одной стороны. С другой стороны — красиво. Не нравится тем, что при использовании DEBUG_ONLY в release версии все равно будет присутствовать мертвый код, и будет jmp для его обхода — и не надо надеяться на оптимизатор!


К>Почему?


Потому что Практика показывает, что на него никогда не надо надеяться. И уж тем более на то, что этот код будет выкинут. Впрочем, для определенных, некритических случаев это не важно.

Но скажем, release версия вообще не использует CRT ни под каким видом. Так при данном способе, что-то сомнительно, чтобы компилятор решился выкинуть такой код, который вызывает fprintf, черта лысого и сбоку бантик. И чтобы линкер этот код не прилинковал

К>К сожалению, С++ не позволяет делать мета-макросы, вида

К>
К>#define BEGIN_DEBUG  { #ifdef DEBUG
К>#define END_DEBUG    #endif }
К>

К>(хотя, может быть, в C99 уже есть что-то такое?)

В C вообще препроцессор убогий, что довольно странно. Веди ноги-то растут из PDP-7 (если не ошибаюсь), на котором уже в те времена был весьма развитой макро-ассемблер. Ключевое слово здесь "макро". В общем, можно было бы и перенять опыт для развитого препроцессора.

McSeem
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[2]: SRC: макрос для DEBUG
От: Serhio Россия  
Дата: 18.11.02 07:38
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Что-то мне это не нравится с одной стороны. С другой стороны — красиво. Не нравится тем, что при использовании DEBUG_ONLY в release версии все равно будет присутствовать мертвый код, и будет jmp для его обхода — и не надо надеяться на оптимизатор! К тому же, будут дополнительные предупреждения компилятора типа "code can never be reached" — я не говорю о MS C++, я говорю о грамотных C++ компиляторах вообще. В общем, у меня противоречивое мнение — "элегантно, но грязно"


А я обычно такие макросы использую:

#ifdef _DEBUG
#define IF_DEBUG(do) do
#define IF_NODEBUG(do)
#else
#define IF_DEBUG(do)
#define IF_NODEBUG(do) do
#endif

В них вышеперечисленые проблемы отсутствуют, но при этом менее красиво.
Re: SRC: макрос для DEBUG
От: Алекс Россия http://wise-orm.com
Дата: 20.11.02 06:23
Оценка:
Здравствуйте, Кодт, Вы писали:

[]

Небольшое добавление:
#ifndef DEBUG_ONLY

  #define DEBUG_ONLY if(!(IS_DEBUG)) {} else
#else

  #define _comment(ccc) ccc##ccc
  #define DEBUG_ONLY _comment(/)

#endif


Теперь в релизе ничего не будет.
Re[2]: SRC: макрос для DEBUG
От: Sergey Россия  
Дата: 20.11.02 14:23
Оценка:
Здравствуйте, Алекс, Вы писали:

А>Небольшое добавление:

А>
А>#ifndef DEBUG_ONLY

А>  #define DEBUG_ONLY if(!(IS_DEBUG)) {} else
А>#else
А>
А>  #define _comment(ccc) ccc##ccc
А>  #define DEBUG_ONLY _comment(/)
А>
А>#endif

А>


А>Теперь в релизе ничего не будет.


Будет, потому что тут есть ошибка. Но идея хорошая. Правильный вариант:


#ifndef DEBUG_ONLY

#if (IS_DEBUG)
  #define DEBUG_ONLY if(false) {} else
#else
  #define _comment(ccc) ccc##ccc
  #define DEBUG_ONLY _comment(/)
#endif

#endif
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[3]: SRC: макрос для DEBUG
От: Кодт Россия  
Дата: 20.11.02 14:57
Оценка:
Здравствуйте, Sergey, Вы писали:

А>>Теперь в релизе ничего не будет.


S>Будет, потому что тут есть ошибка. Но идея хорошая. Правильный вариант:


S>#ifndef DEBUG_ONLY

S>#if (IS_DEBUG)
S>  #define DEBUG_ONLY if(false) {} else
S>#else
S>  #define _comment(ccc) ccc##ccc
S>  #define DEBUG_ONLY _comment(/)
S>#endif

S>#endif


В релизе будет каша.
DEBUG_ONLY one(); two(); three();

DEBUG_ONLY
{
  one(); two(); three();
}

DEBUG_ONLY {
  one(); two(); three();
}

==>
// one(); two(); three();  // two(), three() не попали в релиз

//                         // бессмысленный...
{
  one(); two(); three();
}

// {                       // ... и беспощадный
  one(); two(); three();
}
Перекуём баги на фичи!
Re[3]: SRC: макрос для DEBUG
От: Кодт Россия  
Дата: 20.11.02 15:05
Оценка: 19 (3)
Здравствуйте, Sergey, Вы писали:

<>

По смыслу — это комментирование строки.
Тогда назовем ее:
#ifndef __comment__
  #define __cc__(c) c##c
  #define __comment__ __cc__(/)
#endif

#ifdef DEBUG
  #define DEBUG_LINE
#else
  #define DEBUG_LINE __comment__
#endif

// использование:

DEBUG_LINE unsigned int time1,
DEBUG_LINE              time2;

...

DEBUG_LINE time1 = GetTickCount();
...
DEBUG_LINE time2 = GetTickCount();
DEBUG_LINE ATLTRACE("%u\n", time2-time1);
Перекуём баги на фичи!
Re[4]: SRC: макрос для DEBUG
От: Sergey Россия  
Дата: 20.11.02 16:05
Оценка:
Здравствуйте, Кодт, Вы писали:

К>DEBUG_ONLY {

К> one(); two(); three();
К>}
К>[/c]
==>>
К>
К>// one(); two(); three();  // two(), three() не попали в релиз

К>//                         // бессмысленный...
К>{
К>  one(); two(); three();
К>}

К>// {                       // ... и беспощадный
К>  one(); two(); three();
К>}
К>


Да уж блин, слона-то я и не приметил Ну вас с вашими DEBUG_ONLY, ради DEBUG_LINE и заморачиваться не стоило, держать в релизе никогда не выполняющийся отладочный код тоже не фонтан. Я уж лучше по старинке, с #ifdef'ами буду дальше мучаться.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[4]: SRC: макрос для DEBUG
От: Kirill Prazdnikov  
Дата: 25.11.02 21:18
Оценка:
$> TEST.cpp
#include <stdio.h>

void code() {
false && printf("Debug text\n");
}

$> ICL -Fa test.cpp

PUBLIC ?code@@YAXXZ
?code@@YAXXZ PROC NEAR
$B1$1: ; Preds $B1$0
ret ;5.1

И чго тут линкер увидет ? вызов printf ?
Programmer, MADIA Ltd
Re[5]: SRC: макрос для DEBUG
От: McSeem2 США http://www.antigrain.com
Дата: 26.11.02 03:02
Оценка:
Здравствуйте, Kirill Prazdnikov, Вы писали:

$>> TEST.cpp
KP>#include <stdio.h>

KP>void code() {

KP> false && printf("Debug text\n");
KP>}

$>> ICL -Fa test.cpp

KP> PUBLIC ?code@@YAXXZ

KP>?code@@YAXXZ PROC NEAR
KP>$B1$1: ; Preds $B1$0
KP> ret ;5.1

KP>И чго тут линкер увидет ? вызов printf ?


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

Ну и потом:

extern int my_variable;

void code()
{
 . . .
 if(0)
 {
    . . .черта лысого и сбоку бантик
    my_function(&my_variable);
 }
 . . .
}


Здесь я сам не знаю, как правильно поступить. С одной стороны, можно выкинуть все нафиг. В другой — я ожидаю, что модуль, в котором определена my_variable будет прилинкован, а для этого надо оставить данный код. И не надо говорить, что если не используешь, то и не надо. Прилинковать бывает надо, особенно в случае полиморфных классов со сложным наследованием.
В этом, кстати, есть еще одна опасность. Возьмем фабрики классов, реализованные по типу MFC, ну там, макросы типа DECLARE_DYNAMIC (или как они там — не помню уже). Так вот, в DEBUG все работает, в RELEASE — падает, потому что компилятор выкинул обращение к классу, а линкер его не прилинковал. В результате получаем null-pointer VMT. В общем, данный подход чреват примерно теми же последствиями, что и ASSERT(a = fgets(buf, 100, fd)), но только в гораздо более редких и гораздо более трудноуловимых случаях.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.