Lazarus сообщение об ошибке

Алексеев Е.Р., Чеснокова О.В., Кучер Т.В. Самоучитель по программированию на Free Pascal и Lazarus

121

{Если значение переменной m выходит за пределы области допустимых значений, то выдается сообщение об ошибке.}

else

writeln(‘ОШИБКА ПРИ ВВОДЕ!!!’);

end

end.

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

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

ние в отдельном окне. В общем виде функцию записывают так:

MessageDlg(сообщение, тип_сообщения, [список_кнопок], справка);

где

сообщение – текст, который будет отображен в окне сообщения;

тип_ сообщения – определяет внешний вид окна (табл. 3.2);

список_кнопок – константы (перечисляются через запятую), определяющие тип кнопок окна сообщения (табл. 3.3);

справка – номер окна справочной системы, которое будет вы-

ведено на экран, если нажать F1, параметр равен нулю, если использование справки не предусмотрено.

Таблица. 3.2. Тип окна сообщения.

Параметр

Тип окна сообщения

mtInformation

информационное

mtWarning

предупредительное

mtError

сообщение об ошибке

mtConfirmation

запрос на подтверждение

mtCustom

обычное

Алексеев Е.Р., Чеснокова О.В., Кучер Т.В. Самоучитель по программированию на Free Pascal и Lazarus

122

Таблица. 3.3. Тип кнопки в окне сообщения.

Константа

Кнопка в окне сообщения

mbYes

Да

mbNo

Нет

mbOk

Ок

mbCancel

Отмена

mbAbort

Прервать

mbRetry

Повторить

mbIgnore

Пропустить

mbHelp

Помощь

Вернемся к задаче решения квадратного уравнения (задача 3.3). Нами был рассмотрен алгоритм решения этой задачи и написана программа на языке программирования Free Pascal. Реализуем эту задачу в среде Lazarus. Создадим новый проект41 (рис. 3.20).

Для организации ввода коэффициентов уравнения внедрим на форму четыре объекта типа надпись (Label1, Label2,

Label3, Label4) и три поля ввода (Edit1, Edit2, Edit3).

Корни уравнения или сообщение Рисунок 3.20: Форма для ре- об их отсутствии будем выводить

шения квадратного уравнения в надпись Label542.

Все действия по вычислению корней квадратного уравнения будут выполняться при нажатии кнопки Button1.

При вводе данных в программе могут возникнуть следующие ошибки:

•в поле ввода оказалась строка, которую невозможно преобразовать в число;

•значение коэффициента a равно нулю43.

Для того чтобы не допустить подобных ошибок необходимо контролировать данные, вводимые пользователем. Применим для этой цели встроенную процедуру Val(S,X,Kod), которая преоб-

разовывает строку S в целое или вещественное число X. Если преоб-

41 Подробно о создании проекта см. в первой главе.

42 На этапе конструирования формы Label5.Visible:=false.

43 В этом случае при вычислении корней произойдет деление на ноль.

Алексеев Е.Р., Чеснокова О.В., Кучер Т.В. Самоучитель по программированию на Free Pascal и Lazarus

123

разование прошло успешно, то параметр Kod принимает значение,

равное нулю, а результат преобразования записывается в переменную X. В противном случае Kod содержит номер позиции в строке S, где

произошла ошибка, и содержимое переменной X не меняется. Далее

приведен фрагмент программы с подробными комментариями: procedure TForm1.Button1Click(Sender: TObject);

var

a,b,c,d,x1,x2: real; kod1,kod2,kod3:integer; begin

//Ввод значений коэффициентов уравнения. //Из поля ввода Edit1 считывается строка //символов и преобразовывается в вещественное //число, если преобразование прошло успешно, //то kod1=0 и полученное число записывается //в переменную a.

val(Edit1.Text,a,kod1);

val(Edit2.Text,b,kod2);

val(Edit3.Text,c,kod3);

//Если преобразования прошли успешно, то if (kod1=0) and (kod2=0) and (kod3=0) then

//проверить чему равен первый коэффициент. //Если значение первого коэффициента //равно нулю, то

if a=0 then

//выдать соответствующее сообщение. MessageDlg(‘Введите не нулевое значение а’, mtInformation,[mbOk],0)

else

//иначе перейти к решению уравнения begin

d:=b*b-4*a*c; Label5.Visible:=true; if d<0 then

Label5.Caption:=’В уравнении’+ chr(13)+’нет действительных корней’

else begin

Алексеев Е.Р., Чеснокова О.В., Кучер Т.В. Самоучитель по программированию на Free Pascal и Lazarus

124

x1:=(-b+sqrt(d))/2/a; x2:=(-b-sqrt(d))/(2*a);

Label5.Caption:=’X1=’+

FloatToStr(x1)+chr(13)+

‘X2=’+FloatToStr(x2);

end;

end else

//Преобразование не выполнено, //выдать сообщение.

MessageDlg(‘Введите числовое значение’, mtInformation,[mbOk],0);

end;

Результаты работы программы показаны на рис. 3.21 — 3.24.

Рисунок 3.22: Обработка

ошибки ввода данных — в поле

Рисунок 3.21: Обработка

ввода строка, которую невоз-

ошибки ввода данных — коэффи-

можно преобразовать в число

циент a равен 0

(коэффициент равен символу B)

Рисунок 3.23: Решение квад-

ратного уравнения 3x2+4x+5=0

Рисунок 3.24: Вычисление

(корней нет)

корней квадратного уравнения








English (en)















русский (ru)







Вступление

Stacktrace иногда называют backtrace или call stack. Это список снимков стека, помещенных в стек, содержащих адрес возврата и локальные переменные. Поэтому трассировка стека полезна для отслеживания пути выполнения вашей программы (после вызова процедур).

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

  • -g — генерировать отладочную информацию (в выходном формате по умолчанию для соответствующей платформы, который является dwarf2 на многих платформах)
  • -gl — генерировать номера строк для отладочной информации
  • -gs — генерировать отладочную информацию для устаревшего режима stabs; не используйте одновременно оба ключа -gs и -gw
  • -gw — генерировать отладочную информацию dwarf2; не используйте одновременно оба ключа -gs и -gw
  • -Xg — использовать внешний файл символов отладки

Модуль SysUtils

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

{ Процедуры обработки исключений }
function ExceptObject: TObject;
function ExceptAddr: Pointer;
function ExceptFrameCount: Longint;
function ExceptFrames: PPointer;

Модуль System

Этот модуль содержит некоторые связанные со стеком процедуры:

function SysBackTraceStr(Addr:Pointer): ShortString; // Адрес по умолчанию для преобразования строки, назначенный BackTraceStrFunc
procedure Dump_Stack(var f : text;bp:pointer); // Дамп стека в текстовый файл
procedure DumpExceptionBackTrace(var f:text); // Дамп backtrace в текстовый файл

Процедурная переменная BackTraceStrFunc отвечает за преобразование адреса памяти в строковую отладочную информацию. Поведение по умолчанию реализовано с помощью SysBackTraceStr.

Выводимая информация

Если выбран вывод отладочной информации в виде строк (переключатель компилятора -gl), в программу автоматически включается модуль lineinfo. Этот модуль гарантирует, что отладчики/обработчики исключений смогут найти номера строк выполняющегося кода. Это может быть полезно, если вы не хотите развертывать получающийся исполняемый файл с полной отладочной информацией, но вам нужна полезная информация при возникновении ошибок.

Stabs

Если используется старый формат stabs (-gs), функция BackTraceStrFunc переназначается на StabBackTraceStr.

DWARF

Если выбран формат отладки dwarf (ключ компилятора -gw), в программу автоматически включается модуль lnfodwrf, а функция BackTraceStrFunc преобразуется в DwarfBacktraceStr.

Модуль LCLProc

Этот модуль Lazarus имеет некоторые функции, связанные с отладкой:

//Отладка
procedure RaiseGDBException(const Msg: string);
procedure RaiseAndCatchException;
procedure DumpExceptionBackTrace;
procedure DumpStack;
function GetStackTrace(UseCache: boolean): string;
procedure GetStackTracePointers(var AStack: TStackTracePointers);
function StackTraceAsString(const AStack: TStackTracePointers;
                            UseCache: boolean): string;
function GetLineInfo(Addr: Pointer; UseCache: boolean): string;

Сброс текущего стека вызовов

См. также справку FPC [для получения] подробностей по сбросу стека/исключений:

  • DumpExceptionBackTrace
  • dump_stack
procedure DumpCallStack;
var
  I: Longint;
  prevbp: Pointer;
  CallerFrame,
  CallerAddress,
  bp: Pointer;
  Report: string;
const
  MaxDepth = 20;
begin
  Report := '';
  bp := get_frame;
  // Этот трюк пропустит элемент SendCallstack
  // bp:= get_caller_frame(get_frame);
  try
    prevbp := bp - 1;
    I := 0;
    while bp > prevbp do begin
       CallerAddress := get_caller_addr(bp);
       CallerFrame := get_caller_frame(bp);
       if (CallerAddress = nil) then
         Break;
       Report := Report + BackTraceStrFunc(CallerAddress) + LineEnding;
       Inc(I);
       if (I >= MaxDepth) or (CallerFrame = nil) then
         Break;
       prevbp := bp;
       bp := CallerFrame;
     end;
   except
     { предотвратить бесконечный сброс, если произошло исключение}
   end;
  ShowMessage(Report);
end;

Сброс исключений стека вызовов

Стек вызовов исключения может быть получен через функции модуля SysUtils ExceptAddr, ExceptFrames и ExceptFrameCount.

uses SysUtils;

procedure DumpExceptionCallStack(E: Exception);
var
  I: Integer;
  Frames: PPointer;
  Report: string;
begin
  Report := 'Program exception! ' + LineEnding +
    'Stacktrace:' + LineEnding + LineEnding;
  if E <> nil then begin
    Report := Report + 'Exception class: ' + E.ClassName + LineEnding +
    'Message: ' + E.Message + LineEnding;
  end;
  Report := Report + BackTraceStrFunc(ExceptAddr);
  Frames := ExceptFrames;
  for I := 0 to ExceptFrameCount - 1 do
    Report := Report + LineEnding + BackTraceStrFunc(Frames[I]);
  ShowMessage(Report);
  Halt; // Конец выполнения программы
end;

Обработка исключений

Ручная обработка исключений

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

try
  // ... какая-то операция, которая должна вызвать исключение...
  raise Exception.Create('Test error');
except
  on E: Exception do 
    DumpExceptionCallStack(E);
end;

ExceptProc из модуля System

Если происходит необработанное исключение, выполняется переменная процедуры ExceptProc. Поведение по умолчанию инициализируется процедурой InitExceptions из модуля System. Если вы хотите, эту процедуру можно переназначить на собственный обработчик.

Пример:

procedure CatchUnhandledException(Obj: TObject; Addr: Pointer; FrameCount: Longint; Frames: PPointer);
var
  Message: string;
  i: LongInt;
  hstdout: ^Text;
begin
  hstdout := @stdout;
  Writeln(hstdout^, 'An unhandled exception occurred at $', HexStr(PtrUInt(Addr), SizeOf(PtrUInt) * 2), ' :');
  if Obj is exception then
   begin
     Message := Exception(Obj).ClassName + ' : ' + Exception(Obj).Message;
     Writeln(hstdout^, Message);
   end
  else
    Writeln(hstdout^, 'Exception object ', Obj.ClassName, ' is not of class Exception.');
  Writeln(hstdout^, BackTraceStrFunc(Addr));
  if (FrameCount > 0) then
    begin
      for i := 0 to FrameCount - 1 do
        Writeln(hstdout^, BackTraceStrFunc(Frames[i]));
    end;
  Writeln(hstdout^,'');
end;

Событие TApplication.OnException

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

procedure TMainForm.CustomExceptionHandler(Sender: TObject; E: Exception);
begin
  DumpExceptionCallStack;
  Halt; // Конец выполнения программы
end;   

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Application.OnException := @CustomExceptionHandler;
end;

procedure TMainForm.ButtonClick(Sender: TObject);
begin
  raise Exception.Create('Test');
end;

Обработка исключений доп.потока

Обработка исключений, возникающих в потоках, должна выполняться вручную. Метод основного потока TThread Execute вызывается из функции ThreadProc, расположенной в модуле Classes.

function ThreadProc(ThreadObjPtr: Pointer): PtrInt;
begin
  ...
  try
    Thread.Execute;
  except
    Thread.FFatalException := TObject(AcquireExceptionObject);
  end; 
  ...
end;

В этой функции метод Execute заключен в блок try-except, и все исключения обрабатываются присвоением объекта исключения свойству FatalException объекта TThread как объекта последнего возникшего исключения. Таким образом, исключения не отображаются для пользователя вообще.

В каждом потоке приложения должен быть вставлен отдельный блок try-except, чтобы перехватить все необработанные исключения с помощью специального обработчика исключений.

procedure TMyThread.Execute;
begin
  try
    // какой-нибудь ошибочный код
  except
    on E: Exception do 
      CustomExceptionThreadHandler(Self, E);
  end;
end;

Затем CustomExceptionThreadHandler может получить стек вызовов исключений и управлять отображением сообщений об ошибках или протоколированием отчетов журнала в файл. Поскольку обработчик выполняется из потока, показ диалога сообщений должен быть безопасным для потока с использованием метода Synchronize.

procedure TMainForm.CustomExceptionHandler(Thread: TThread; E: Exception);
begin
  Thread.Synchronize(DumpExceptionCallStack);
end;

Использование map-файла

Используйте ключ компилятора -Xm для генерации map-файла.

Исключения в DLL

todo

См.также

  • Profiling
  • Creating a Backtrace with GDB
  • MultiLog — протоколирующий пакет
  • log4delphi — протоколирующий пакет

Внешние ссылки

  • esprinter — инструмент для получения трассировки стека из запущенной программы FreePascal, заданной идентификатором процесса и идентификатором потока (для Win32)
  • PascalBugReports — проект, имитирующий EurekaLog / MadExcept, но долгое время не разрабатывался

First, a big thank you to TLama for all the explanations and directions. I have to accept his answer as I’ve built mine based on that. I’m only posting this as an answer so that another person who’s a beginner to Lazarus may find this useful. I’m not in anyway suggesting that this is the best thing to do, but this is what I want to do for now. That is, when a certain exception occurs, I want to trap it and deal with it.

Given that,

  1. I am dynamically creating a set of TPanels to look like buttons
  2. Each TPanel has assigned to it a mouseclick event

Let’s assume that there are 10 such ‘buttons’ (actually TPanels).

The problem:
When I first click on the first button, I can then click on another one (eg: the 5th). But if I first click the 5th or anything else other than the first, the program throws the ‘Access violation’ error. Note however, that the program doe not crash despite the ugly warning about data corruption and stuff. So the user can simply click ok and continue. Strangely then, with subsequent clicks, this problem reduces! I know that’s funny.

Now, as explained by TLama, the error occurs when the mouse is being released AFTER clicking a button.

But here’s my problem… I don’t have a mouseup event. That’s part of Pascal.

So now, I want to ignore the mouseup event (at least for now). There MUST be a better way.

But there’s another issue. I cannot ignore what I don’t have! And I don’t have a mouseup event. So I finally decided to capture this error at application level like this:

On the main form, I put this code:

procedure TfrmMainForm.CatchErr(Sender: TObject; e:exception);
begin
  if e.Message <> 'Access violation' then ShowMessage('MOL: ' + e.Message);
end; 

And then on form create, I put this:

Application.OnException:=@CatchErr;

And (for now) I can circumvent this issue.

Once again, as TLama has indicated, this is not good advice. Nonetheless, it is what I wanted to do.

Also what makes it harder is that the error is occuring in mouseup, which is in control.inc. And this is not my file. Rather it’s part of Lazarus. I think it would be better if we had a way of telling Lazarus to delete that event for the TPanels in the code. I think it involves re-writing a derived class for it and I don’t see how that’s any good for me right now :)

Thanks again TLama!

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

При разработке приложений бывает иногда необходимо вывести какую-либо информацию в Event Log. В Delphi для этих целей удобно пользоваться методами OutputDebugString, но так как это путь исключительно для Windows, то в случае работы с Lazarus, например в Debian или Slax такой подход не подойдет. В Lazarus, для того чтобы вывести какое-либо сообщение при отладке приложения имеется несколько способов речь о которых пойдет далее.

Если всё-таки Windows?

Если Вы планируете использовать Lazarus исключительно в среде Windows и, то, в принципе, никто вам не мешает подключить в uses модуль Windows и продолжать пользоваться уже привычными методами OutputDebugString, правда ваши сообщения будут попадать не в окно «Сообщения» к которому мы привыкли в Delphi, а в отдельное под названием «Журнал событий». Чтобы добраться до журнала событий, необходимо открыть в меню «Вид — Окна отладки — Журнал событий»

С пользовательским сообщением журнал событий выглядит вот так:

В принципе, ничего для тех, кто привык работать в Delphi, не поменяется за исключением расположения сообщений — в отдельном окне.

Аналог OutputDebugString в Lazarus «из коробки»

Для пользователей Lazarus в Linux всё не на много сложнее. Дело в том, что в Lazarus присутствует модуль dbugintf.pas, выводить различные отладочные сообщения, правда опять же, в отдельном окне. Чтобы эта возможность заработала, необходимо выполнить следующие действия:

1.Собрать утилиту  debugserver, которая находится в папке с Lazarus по пути: %Lazarus%\tools\debugserver\

По сути, эта утилита сильно напоминает «Журнал событий», о котором шла речь выше. Вот как выглядит пустой debugserver:

2. Добавить debugserver в список внешних средств Lazarus. Для этого заходим в меню: Сервис — Настроить внешние средства:

добавить утилиту в список следующим образом:

Теперь debugserver появится в меню Lazarus:

3. Подключить в uses любого модуля вашего проекта модуль dbugintf и включить вывод сообщений в окно debugserver, используя следующий метод:

procedure SetDebuggingEnabled(const AValue : boolean);

Думаю, тут всё понятно и без комментариев — передача в метод значение True включается вывод сообщений, False — отключает. Для вывода различных сообщений в debugserver можно воспользоваться следующими методами:

procedure SendBoolean(const Identifier: string; const Value: Boolean);
procedure SendDateTime(const Identifier: string; const Value: TDateTime);
procedure SendInteger(const Identifier: string; const Value: Integer; HexNotation: Boolean = False);
procedure SendPointer(const Identifier: string; const Value: Pointer);
procedure SendDebugEx(const Msg: string; MType: TDebugLevel);
procedure SendDebug(const Msg: string);
procedure SendMethodEnter(const MethodName: string);
procedure SendMethodExit(const MethodName: string);
procedure SendSeparator;
procedure SendDebugFmt(const Msg: string; const Args: array of const);
procedure SendDebugFmtEx(const Msg: string; const Args: array of const; MType: TDebugLevel);

Чтобы продемонстрировать работу методов, напишем следующий тестовый код на Lazarus:

procedure TForm1.Button2Click(Sender: TObject);
var b: boolean;
    i: integer;
    d: TDateTime;
begin
  SetDebuggingEnabled(True);
  SendMethodEnter('Button2Click Enter');
  b:=True;
  SendBoolean('b',b);
  i:=100;
  SendInteger('i',i,False);
  SendInteger('i as hex',i,True);
  d:=Now;
  SendDateTime('d',d);
  SendSeparator;
  SendDebugEx('Это сообщение будет выглядеть в окне debugserver как ошибка', dlError);
  SendMethodExit('Button2Click Enter');
end;

Здесь мы воспользовались различными методами модуля dbugintf и отправили в debugserver несколько сообщений, которые будут выглядеть следующим образом:

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

Как видите, в Lazarus можно без проблем выводить отладочные сообщения практически так же, как мы привыкли делать это в Delphi за одним лишь различием в том, что в Lazarus это будет работать в любой операционной системе и, поэтому, требуется дополнительный шаг настройки утилиты debugserver.

На сегодня всё. Продолжаем разбираться с Lazarus и попутно в нем же работать :)

5
3
голоса

Рейтинг статьи

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

Аннотация: Лекция носит факультативный характер. Здесь мы рассматриваем виды допускаемых в программировании ошибок, способы тестирования и отладки программ, инструменты встроенного отладчика.

Цель лекции

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

Тестирование и отладка программы

Чем больше опыта имеет программист, тем меньше ошибок в коде он совершает. Но, хотите верьте, хотите нет, даже самый опытный программист всё же допускает ошибки. И любая современная среда разработки программ должна иметь собственные инструменты для отладки приложений, а также для своевременного обнаружения и исправления возможных ошибок. Программные ошибки на программистском сленге называют багами (англ. bug — жук), а программы отладки кода — дебаггерами (англ. debugger — отладчик). Lazarus, как современная среда разработки приложений, имеет собственный встроенный отладчик, работу с которым мы разберем на этой лекции.

Ошибки, которые может допустить программист, условно делятся на три группы:

  1. Синтаксические
  2. Времени выполнения (run-time errors)
  3. Алгоритмические

Синтаксические ошибки

Синтаксические ошибки легче всего обнаружить и исправить — их обнаруживает компилятор, не давая скомпилировать и запустить программу. Причем компилятор устанавливает курсор на ошибку, или после неё, а в окне сообщений выводит соответствующее сообщение, например, такое:

Найденная компилятором синтаксическая ошибка - нет объявления переменной i

Рис.
27.1.
Найденная компилятором синтаксическая ошибка — нет объявления переменной i

Подобные ошибки могут возникнуть при неправильном написании директивы или имени функции (процедуры); при попытке обратиться к переменной или константе, которую не объявляли (
рис.
27.1); при попытке вызвать функцию (процедуру, переменную, константу) из модуля, который не был подключен в разделе uses; при других аналогичных недосмотрах программиста.

Как уже говорилось, компилятор при нахождении подобной ошибки приостанавливает процесс компиляции, выводит сообщение о найденной ошибке и устанавливает курсор на допущенную ошибку, или после неё. Программисту остается только внести исправления в код программы и выполнить повторную компиляцию.

Ошибки времени выполнения

Ошибки времени выполнения (run-time errors) тоже, как правило, легко устранимы. Они обычно проявляются уже при первых запусках программы, или во время тестирования. Если такую программу запустить из среды Lazarus, то она скомпилируется, но при попытке загрузки, или в момент совершения ошибки, приостановит свою работу, выведя на экран соответствующее сообщение. Например, такое:

Сообщение Lazarus об ошибке времени выполнения

Рис.
27.2.
Сообщение Lazarus об ошибке времени выполнения

В данном случае программа при загрузке должна была считать в память отсутствующий текстовый файл MyFile.txt. Поскольку программа вызвала ошибку, она не запустилась, но в среде Lazarus процесс отладки продолжается, о чем свидетельствует сообщение в скобках в заголовке главного меню, после названия проекта. Программисту в подобных случаях нужно сбросить отладчик командой меню «Запуск -> Сбросить отладчик«, после чего можно продолжить работу над проектом.

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

Если программу запустить из самой Windows, при возникновении этой ошибки появится такое же сообщение. При этом если нажать «OK«, программа даже может запуститься, но корректно работать все равно не будет.

Ошибки времени выполнения бывают не только явными, но и неявными, при которых программа продолжает свою работу, не выводя никаких сообщений, а программист даже не догадывается о наличии ошибки. Примером неявной ошибки может служить так называемая утечка памяти. Утечка памяти возникает в случаях, когда программист забывает освободить выделенную под объект память. Например, мы объявляем переменную типа TStringList, и работаем с ней:

begin
  MySL:= TStringList.Create;
  MySL.Add('Новая строка');
end;
    

В данном примере программист допустил типичную для начинающих ошибку — не освободил класс TStringList. Это не приведет к сбою или аварийному завершению программы, но в итоге можно бесполезно израсходовать очень много памяти. Конечно, эта память будет освобождена после выгрузки программы (за этим следит операционная система), но утечка памяти во время выполнения программы тоже может привести к неприятным последствиям, потребляя все больше и больше ресурсов и излишне нагружая процессор. В подобных случаях после работы с объектом программисту нужно не забывать освобождать память:

begin
  MySL:= TStringList.Create;
  MySL.Add('Новая строка');
  ...; //работа с объектом
  MySL.Free; //освободили объект
end;
    

Однако ошибки времени выполнения могут случиться и во время работы с объектом. Если есть такой риск, программист должен не забывать про возможность обработки исключительных ситуаций. В данном случае вышеприведенный код правильней будет оформить таким образом:

begin
  try
    MySL:= TStringList.Create;
    MySL.Add('Новая строка');
    ...; //работа с объектом
  finally
    MySL.Free; //освободили объект, даже если была ошибка
  end;
end;
    

Итак, во избежание ошибок времени выполнения программист должен не забывать делать проверку на правильность ввода пользователем допустимых значений, заключать опасный код в блоки try…finally…end или try…except…end, делать проверку на существование открываемого файла функцией FileExists и вообще соблюдать предусмотрительность во всех слабых местах программы. Не полагайтесь на пользователя, ведь недаром говорят, что если в программе можно допустить ошибку, пользователь эту возможность непременно найдет.

Алгоритмические ошибки

Если вы не допустили ни синтаксических ошибок, ни ошибок времени выполнения, программа скомпилировалась, запустилась и работает нормально, то это еще не означает, что в программе нет ошибок. Убедиться в этом можно только в процессе её тестирования.

Тестирование — процесс проверки работоспособности программы путем ввода в неё различных, даже намеренно ошибочных данных, и последующей контрольной проверке выводимого результата.

Если программа работает правильно с одними наборами исходных данных, и неправильно с другими, то это свидетельствует о наличии алгоритмической ошибки. Алгоритмические ошибки иногда называют логическими, обычно они связаны с неверной реализацией алгоритма программы: вместо «+» ошибочно поставили «-«, вместо «/» — «*», вместо деления значения на 0,01 разделили на 0,001 и т.п. Такие ошибки обычно не обнаруживаются во время компиляции, программа нормально запускается, работает, а при анализе выводимого результата выясняется, что он неверный. При этом компилятор не укажет программисту на ошибку — чтобы найти и устранить её, приходится анализировать код, пошагово «прокручивать» его выполнение, следя за результатом. Такой процесс называется отладкой.

Отладка — процесс поиска и устранения ошибок, чаще алгоритмических. Хотя отладчик позволяет справиться и с ошибками времени выполнения, которые не обнаруживаются явно.

Понравилась статья? Поделить с друзьями:
  • Lego star wars the force awakens ошибка
  • Lazarus ошибка отладчика ой отладчик попал
  • Lego city undercover ошибка
  • Lazarus ошибка sqlite3 dll
  • Lego batman ошибка