Войти
ФлеймФорумПрограммирование

Принципы и приёмы отладки

Страницы: 1 2 3 4 Следующая »
#0
17:11, 23 ноя. 2018

  Я сейчас переписываю старый алгоритм (надо его оптимизировать), и постоянно отлавливаю всё новые баги. Возник вопрос: какие на данный момент есть приёмы отладки, которыми я пока не пользовался.
  Точнее, в этой теме два вопроса: конкретно про Delphi XE8 – что тут интересного по сравнению с Delphi7. Второй вопрос – скорее общая “философия программирования”.
  Я часто испытываю неудобства с отладкой. Например, обычные переменные можно посмотреть на breakpoint-е, а более сложные (скажем метод Get(I) у класса, или конкретный элемент массива) никак.
  В идеале мне хотелось бы во время отладки запустить какую-то подпрограмму из моего кода, вроде того же метода Get(I). В других ЯП такое есть?
  Конкретно с Delphi XE я не могу разобраться, как при нажатии на кнопку паузы перейти на участок моего кода, который выполняется в данный момент. Раньше в Delphi 7 я это делал, а теперь могу только перейти на отладку ассемблерного кода, который я не понимаю.
  Я начал пробовать использовать инлайновые функции в Delphi XE8, и обнаружил что они жутко неудобные: например инлайновая функция не может обратиться к переменной уровнем выше (в той функции, которая её вызывает).
  Мне кажется, причина этого в том, что инлайновые функции намного затрудняют отладку с точки зрения компилятора. Тут нужен какой-то препроцессор/прекомпилятор, вроде того который я предложил в этой теме.
  Говоря о прекомпиляторах, я добавлю что, по-моему, хороший ЯП должен компилировать в двух режимах: отладочный и финальный. В отладочном не будут инлайниться функции, поэтому отладчик сможет нормально взаимодействовать с кодом, а в финальном режиме код будет “размножаться” (размножение циклов, инлайновые фунции и т.п.) для скорости.
  Теперь вопрос более практический: какие вы используете собственные приёмы и хитрости для отладки, например вспомогательный код?
  У меня, например, есть функция DBError:

procedure DBError;
begin
  raise exception.create(‘Algorithm debug error’,’MyProgram’);
end;

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

varnum := -1;
for qq:=0 to variantsfrom[num1].varcount-1 do
  if variantsfrom[num1].vars[qq]=num2 then
     begin
       varnum:=qq;
       break;
     end;
if varnum=-1 then DBError;

В данном случае я знаю, что varnum не должен быть равен -1, а если равен – значит в моём алгоритме точно есть косяк. Мне кажется, полезно часто писать такие вставки почаще. Но при компиляции финальной версии их лучше убрать для скорости. Наверно тут надо в Delphi использовать $IFDEF?
Ещё у меня есть процедура DBNop:

procedure DBNop;
  begin

  end;

Это бывает полезно, чтобы поставить breakpoint на пустое место.

#1
17:17, 23 ноя. 2018

Vit Nhoc
> а более сложные (скажем метод Get(I) у класса, или конкретный элемент массива)
> никак.
Можно посмотреть в watch окне поставив allow function call в вотч переменной

#2
17:18, 23 ноя. 2018

Vit Nhoc
> как при нажатии на кнопку паузы перейти на участок моего кода, который
> выполняется в данный момент
Открыть окно threads и двойным щелчком выбрать основной поток

#3
17:20, 23 ноя. 2018

Vit Nhoc
> В данном случае я знаю, что varnum не должен быть равен -1, а если равен –
> значит в моём алгоритме точно есть косяк. Мне кажется, полезно часто писать
> такие вставки почаще. Но при компиляции финальной версии их лучше убрать для
> скорости. Наверно тут надо в Delphi использовать $IFDEF?
Для этого есть Assert

#4
17:30, 23 ноя. 2018

кстати делфа норм дает посмотреть массивы, даже если он длинной 100500.
вот студия при отладке юнити , когда открываешь большой массив - знатно втупливает, опционально зависает наглухо.

в отладке всякая шушера в IFDEF ага

 {$ifdef DEBUG}
    WriteLn('db size ',CurrentClient.equipmodels.ItemsDataSet.RecordCount);
 {$endif}
#5
17:32, 23 ноя. 2018

Vit Nhoc
> У меня, например, есть функция DBError:
чет не очень информативно, под отладчиком ты поймаешь откуда приплыл экспшн, а без отладчика как?

#6
17:37, 23 ноя. 2018

Vit Nhoc
> Раньше в Delphi 7 я это делал, а теперь могу только перейти на отладку
> ассемблерного кода, который я не понимаю.
call stack посмотреть, наверняка в нем будет процедура из которой этот ассемблерный код вызван.

> Например, обычные переменные можно посмотреть на breakpoint-е, а более сложные
> (скажем метод Get(I) у класса, или конкретный элемент массива) никак.
правой кнопкой->Debug->Evaluate\Modify

#7
(Правка: 18:10) 17:41, 23 ноя. 2018
Vit Nhoc
> for qq:=0 to variantsfrom[num1].varcount-1 do
как мило, переменную цикла достаточно написать один раз, вместо трёх.

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

#8
17:55, 23 ноя. 2018

entryway
В Ц отродясь не было никаких "переменных цикла".

#9
18:20, 23 ноя. 2018

kipar
> > Например, обычные переменные можно посмотреть на breakpoint-е, а более
> > сложные
> > (скажем метод Get(I) у класса, или конкретный элемент массива) никак.
> правой кнопкой->Debug->Evaluate\Modify

Спасибо, хотя это видимо позволяет только изменить на лету обычную переменную, но не вызвать процедуру типа Set(I) (т.е. таким способом свойства VCL-классов не поменяешь).

Mira
> > У меня, например, есть функция DBError:
> чет не очень информативно, под отладчиком ты поймаешь откуда приплыл экспшн, а
> без отладчика как?

Наверно никак.
Собственно я и с исключениями не научился работать, я при отладке сейчас просто меняю код в процедуре DBError - меняю вызов исключения на процедуру DBNop, чтобы поставить на ней брекпоинт. Сорри если всё это ужасно непрофессионально...

MrShoor
> > а более сложные (скажем метод Get(I) у класса, или конкретный элемент
> > массива)
> > никак.
> Можно посмотреть в watch окне поставив allow function call в вотч переменной

Поясните, что такое watch окно? Это что-то по правой кнопке мыши?

#10
(Правка: 18:27) 18:26, 23 ноя. 2018

Vit Nhoc
> Спасибо, хотя это видимо позволяет только изменить на лету обычную переменную,
> но не вызвать процедуру типа Set(I) (т.е. таким способом свойства VCL-классов
> не поменяешь)
никогда не пробовал менять, но счас проверил - свойства меняются.
Произвольную процедуру (не связанную со свойством) - да, не вызвать.

#11
(Правка: 19:05) 19:03, 23 ноя. 2018

бывало отлаживаешь ченеть, наводишь мышку на property с Getter посмотреть значение, а там в геттере вычисления какие-то с поврежденим памяти.
и все , давай досвидания, IDE потухла =)

впрочем класть вычисления в геттер - плохая манера

#12
19:19, 23 ноя. 2018

Vit Nhoc
> В данном случае я знаю, что varnum не должен быть равен -1, а если равен –
> значит в моём алгоритме точно есть косяк. Мне кажется, полезно часто писать
> такие вставки почаще. Но при компиляции финальной версии их лучше убрать для
> скорости. Наверно тут надо в Delphi использовать $IFDEF?
Вау, ты изобрёл ассерт!

#13
7:26, 24 ноя. 2018

MrShoor
> > как при нажатии на кнопку паузы перейти на участок моего кода, который
> > выполняется в данный момент
> Открыть окно threads и двойным щелчком выбрать основной поток

Прошу прощения, где здесь окно threads?

+ Показать
#14
8:43, 24 ноя. 2018

1 frag / 2 deaths
> > В данном случае я знаю, что varnum не должен быть равен -1, а если равен –
> > значит в моём алгоритме точно есть косяк. Мне кажется, полезно часто писать
> > такие вставки почаще. Но при компиляции финальной версии их лучше убрать для
> > скорости. Наверно тут надо в Delphi использовать $IFDEF?
> Вау, ты изобрёл ассерт!

Честно говоря я не знал про assert, точнее забыл.
Но я думаю что DBError имеет свою преимущества перед ассертом: по названию процедуры видно, что она именно для отладки, и в финальной версии её можно убрать; также можно вызывать её с параметром, например строкой, чтобы отлавливать где именно срабатывает этот ассерт:

if varnum=-1 then DBError('Found -1 in Variantsfrom');
Страницы: 1 2 3 4 Следующая »
ФлеймФорумПрограммирование