В связи с тем что у первого курса возникает много вопросов о том что такое режим отладки и как его сотворить мне пришлось отвлечься от проэктирования эпичной развязки в TTD и написать этот пост. Эх пичалька.
Для начала поймем что ОН от нас хочет, я думаю все поняли кто подрозумевается под НИМ, в дальнейшем так и будем его упоминать, дабы не тратить время и знакоместо под ненужные эпитеты =).
Отладка на мой скромный взгляд состоит из 2ух вещей:
Это все по поводу отладочной печати, теперь займемся трасировкой функций.
Трасировка будет заключатся в том что бы в отладочный вывод печаталось когда и какая функция была вызвана.
Есть несколько методик, я покажу 2 из них.
Первая заключатся в том что бы использовать макроссы заменяющие обычный вызов функции, и ее объявляение.
Собствественно пример:
Для начала поймем что ОН от нас хочет, я думаю все поняли кто подрозумевается под НИМ, в дальнейшем так и будем его упоминать, дабы не тратить время и знакоместо под ненужные эпитеты =).
Отладка на мой скромный взгляд состоит из 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);А этот макросс мы будем использовать для вызова функции, как видим помимо вызова он так же напечатает нам какую именно функцию мы вызвали и когда она завершила работу.
Собствественно пример:
#includeFILE* 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; }
Да мне было впадлу показать второй пример, он заключается всего лишь в макроподстановке { на { printf("Entering function"); менее информативно.
ОтветитьУдалитьПредлагаю первому курсу придумать что-то интерестноее на эту тему. Например как печатать при вызове функции аргументы :3 Лучшему генератору идей подарю шоколадку
OpenTTD? За отладку - спасибо.
ОтветитьУдалитьУгу, OpenTTD тащит~ Будет чо поделать на философии завтра :D
ОтветитьУдалить