Gigaset Fortunes

23 февр. 2011 г.

DEBUG or not DEBUG...

В связи с тем что у первого курса возникает много вопросов о том что такое режим отладки и как его сотворить мне пришлось отвлечься от проэктирования эпичной развязки в TTD и написать этот пост. Эх пичалька.




Для начала поймем что ОН от нас хочет, я думаю все поняли кто подрозумевается под НИМ, в дальнейшем так и будем его упоминать, дабы не тратить время и знакоместо под ненужные эпитеты =).

Отладка на мой скромный взгляд состоит из 2ух вещей:

  1. Отладочные сообщения
  2. Трасировка выполнения программы
Начнем с простого, отладочные сообщения. Исходя из названия это сообщения который должны возникать только при отладке, и исчезать когда мы запускаем релизовую версию программы.
Напишем простенький макрос:
#define DPRINT(format,...)  fprintf(stdlog,format"\n",__VA_ARGS__);
При вызове этот макросс развернется в обычный fprintf
#define DPRINT(format,...)  fprintf(stdlog,format"\n",__VA_ARGS__);
DPRINT("a = %a",a)
fprintf(stdout,"a = %a",a);
Теперь модифицируем код таким образом что бы печать происходила только когда мы в отладочном режиме.
#ifdef  __DEBUG__
#define DPRINT(format,...)  fprintf(stdlog,format"\n",__VA_ARGS__);
#else
#define DPRINT(format,...)
#endif//__DEBUG__
Второй #define нужен нам для того что бы когда мы собирем проект без флага __DEBUG__ мы имели рабочий код, и никаких unresolved externals.

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

Есть несколько методик, я покажу 2 из них.
Первая заключатся в том что бы использовать макроссы заменяющие обычный вызов функции, и ее объявляение.

#define FUNCTION(rtype,F,...) char* fsig_##F = #rtype" "#F"("#__VA_ARGS__")";\
    rtype X(__VA_ARGS__);
Данный макрос мы будем использовать для объявления функции. Как мы можем видеть он раскрывается в само объявление, но помимо этого добавляет глобальную переменную которая хранит сигнатуру функции.
#define CALL(F,...) fprintf(stdlog,"Called function \"%s\"\n",fsig_##F); \
   F(__VA_ARGS__); \    
                        fprintf(stdlog,"Exited from function \"%s\"\n",#F);
А этот макросс мы будем использовать для вызова функции, как видим помимо вызова он так же напечатает нам какую именно функцию мы вызвали и когда она завершила работу.

Собствественно пример:
#include 

FILE* stdlog;

#define __DEBUG__

#ifdef  __DEBUG__

#define FUNCTION(rtype,F,...) char* fsig_##F = #rtype" "#F"("#__VA_ARGS__")";\
        rtype X(__VA_ARGS__);
#define CALL(F,...)    fprintf(stdlog,"Called function \"%s\"\n",fsig_##F); \
        F(__VA_ARGS__);         \
        fprintf(stdlog,"Exited from function \"%s\"\n",#F);
#define DPRINT(format,...)  fprintf(stdlog,format"\n",__VA_ARGS__);

#else

#define FUNCTION(rtype,X,...)   rtype X(__VA_ARGS__);
#define CALL(F,...)    F(__VA_ARGS__);
#define DPRINT(format,...)  

#endif//__DEBUG__

FUNCTION(int,foo,int a,int b)


int main (int argc, const char * argv[]) {
    int a;
    stdlog = stdout;
    a = CALL(foo,10,15);
    DPRINT("foo is %d",a); 
    return 0;
}

int foo(int a,int b)
{
 DPRINT("a = %d",a)
 DPRINT("b = %d",b)
 
 return a+b;
}

3 комментария:

  1. Да мне было впадлу показать второй пример, он заключается всего лишь в макроподстановке { на { printf("Entering function"); менее информативно.

    Предлагаю первому курсу придумать что-то интерестноее на эту тему. Например как печатать при вызове функции аргументы :3 Лучшему генератору идей подарю шоколадку

    ОтветитьУдалить
  2. Угу, OpenTTD тащит~ Будет чо поделать на философии завтра :D

    ОтветитьУдалить