Как проверить ошибку в паскале

1 / 1 / 0

Регистрация: 25.11.2013

Сообщений: 40

1

Как в Паскале проверять текст на ошибки?

02.12.2013, 23:13. Показов 5490. Ответов 12


Студворк — интернет-сервис помощи студентам

После набора текста выходит масса ошибок и чтоб их увидеть, приходится сидеть часами… Иногда терпения не хватает. Подскажите пожалуйста как решить эту проблему? Есть ли такое, что программа автоматом находит ошибки и исправляет?))



0



$ su

1605 / 520 / 97

Регистрация: 18.11.2010

Сообщений: 2,807

Записей в блоге: 2

03.12.2013, 00:17

2

Он при компиляции при ошибке останавливает возле нее курсор, что еще надо?
Или ты о другом?



2



1 / 1 / 0

Регистрация: 25.11.2013

Сообщений: 40

03.12.2013, 20:47

 [ТС]

3

А МОЯ ПРОГРАММА НЕ СТАВИТ КУРСОР… МОЖЕТ ПОСОВЕТУЕТЕ КАКУЮ И ГДЕ СКАЧАТЬ?



0



$ su

1605 / 520 / 97

Регистрация: 18.11.2010

Сообщений: 2,807

Записей в блоге: 2

04.12.2013, 17:36

4

Вы хотите проверять текст(код) в трансляторе? Или текст который выдает программа после выполнения, я вас не пойму.



0



0 / 0 / 0

Регистрация: 03.12.2013

Сообщений: 20

04.12.2013, 18:34

5

ctrl + F9.курсор стоит сразу после ошибки

Добавлено через 40 минут
попробуйте зайти на офф сайт,там поискать…а так в принципе Turbo Pascal 7.0



0



0 / 0 / 0

Регистрация: 25.11.2013

Сообщений: 16

04.12.2013, 23:05

6

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

Добавлено через 1 минуту
У меня как раз Турбо Паскаль 7, причем две разных версии, ни в одном из них после комбинации ctrl + F9 курсор не встает на ошибку, просто показывает код ошибки. Может программа косячная????



0



$ su

1605 / 520 / 97

Регистрация: 18.11.2010

Сообщений: 2,807

Записей в блоге: 2

04.12.2013, 23:30

7

Попробуй через PascalABC там он точно ставит курсор на строке с ошибкой(в турбике тоже ставит, но я не знаю что у вас). Или же, если тебе не удобно то просто проверяй ошибки через PascalABC. Все программы написанные на Турбо спокойно запускаются на нем.



0



561 / 484 / 168

Регистрация: 14.02.2012

Сообщений: 1,561

04.12.2013, 23:42

8

Цитата
Сообщение от ntlinuxnt
Посмотреть сообщение

Все программы написанные на Турбо спокойно запускаются на нем.

Не все. Для графики в Turbo Pascal используется модуль Graph и надо самому настраивать параметры экрана(инициализация драйвера графики и прочее). В Pascal ABC всё реализовано через GraphABC без всяких предварительных настроек.



0



$ su

1605 / 520 / 97

Регистрация: 18.11.2010

Сообщений: 2,807

Записей в блоге: 2

04.12.2013, 23:54

9

У вас именно работу с графикой надо проверять? Просто я не знаю почему у вас курсор не становится вы под какой ОС работаете с Турбо?



0



50 / 42 / 25

Регистрация: 05.12.2013

Сообщений: 275

05.12.2013, 15:22

10

Сейчас каких только Турбо нет, и чаще всего такие лаги возникают на русских версиях. Если у Вас русская, то лучше скачать английскую.



0



1 / 1 / 0

Регистрация: 25.11.2013

Сообщений: 40

06.12.2013, 10:24

 [ТС]

11

Спасибо за рекомендации, у меня две версии, одна английская, вторая русская. С графикой работы пока не делала, но скорей всего придется. ОС у меня WindowsXP.



0



50 / 42 / 25

Регистрация: 05.12.2013

Сообщений: 275

06.12.2013, 14:27

12

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



0



0 / 0 / 0

Регистрация: 25.11.2013

Сообщений: 16

06.12.2013, 20:33

13

Ясно. Благодарю!



0



Содержание

Отладка программ в Turbo Pascal

Автор: volvo877 (он же и volvo71)

Ссылка на оригинал статьи

FIXME (не хватает картинок из статьи)

Каждый программист знает, что программу надо не только написать, иначе говоря —
«заставить работать», а еще и отладить, т.е. заставить ее работать правильно…
Для того, чтобы делать это быстро и эффективно, желательно научиться
пользоваться встроенными в IDE средствами отладки программ…

Интегрированная интерактивная среда разработки программ Borland Pascal (IDE)
включает в себя ряд средств, облегчающих разработку программ: автоматическое
управление проектами, средств обеспечения модульной структуры программы,
быструю компиляцию и простые в использовании оверлеи. Но, несмотря на все это,
Ваша программа все равно может содержать ошибки, что не позволит ей корректно
работать.

IDE для DOS Borland Pascal предоставляет вам инструментальные средства для
отладки программ, то есть поиска и исправления ошибок. В этой статье
описываются инструментальные средства и процедуры отладки программы в
интегрированной среде Борланд Паскаль (большинство описанных возможностей
применимо также к IDE FreePascal-я).

Что такое отладка?

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

Какие существуют виды ошибок?

Существует три основных типа ошибок:

  • Ошибки этапа компиляции

  • Ошибки этапа выполнения

  • Логические ошибки

Ошибки этапа компиляции

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

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

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

Ошибки этапа выполнения

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

Когда такая ошибка обнаруживается, выполнение программы завершается, и выводится сообщение следующего вида:

Run-time error ## at seg:ofs

Если Вы выполняете программу из IDE, она автоматически находит оператор,
вызвавший ошибку (как и в случае синтаксических ошибок). Если же программа выполняется вне IDE (EXE-файл запускается из командной строки или файлового менеджера ОС), то вы можете запустить IDE и, чтобы найти вызвавший ошибку оператор, использовать команду Search → Find Error, которая дает вам адрес сегмента и смещения (seg:ofs).

Логические ошибки

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

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

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

Пошаговый прогон: какая разница между F4, F7 и F8?

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

  • Выполнять инструкции по шагам

  • Трассировать инструкции

  • Выполнять программу до заданной точки

  • Находить определенную точку

  • Выполнять сброс программы

Само по себе выполнение программы по шагам может быть недостаточно полезным, разве что поможет найти то место, где что-то происходит совершенно неверно. Но управляемое выполнение дает Вам возможность проверять состояние программы и ее данных, например, отслеживать вывод программы и ее переменные.

Что такое шаг?

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

Все выполнение в отладчике, включая выполнение по шагам, трассировку и останов, основывается на строках. Подсвечивая строку, встроенный отладчик всегда сообщает Вам, какую строку он выполнит на следующем шаге (строка выполнения). Строка выполнения выводится цветом, отличным от нормального цвета. Благодаря этому Вы можете легко видеть, где находитесь.

Выполнение программы по шагам

Выполнение по шагам — это простейший способ выполнения программы по
элементарным фрагментам. Выбор команды Run → Step Over или нажатие клавиши F8 вызывает выполнение отладчиком всего кода в операторе, указанном строкой выполнения, включая любые вызываемые на ней процедуры или функции, пока управление не вернется обратно к вам. После этого строка выполнения указывает следующий выполняемый оператор.

Возьмем, например, следующую программу:

program StepTest;
 
  function Negate(X: Integer): Integer;
  begin
    Negate := -X;
  end;
 
var
  I: Integer;
begin
  for I := 1 to 10 do Writeln(Negate(I));
end.

Если в окне редактирования Вы выведете StepTest и нажмете клавишу F8, то строка выполнения перемещается на оператор begin в начале основного цикла, поскольку это первое, что выполняется в программе. Второе нажатие клавиши F8 выполняет begin и перемещает строку выполнения вниз до оператора for на следующей строке.

После этого нажатие F8 вызывает выполнение всего цикла for; на экран
пользователя выводятся числа от -1 до -10, а строка выполнения перемещается к end.

Хотя функция Negate и вызывается 10 раз, строка выполнения никогда на нее не перемещается. Выполнение по шагам позволяет отладчику не показывать детали любых вызовов для отдельной строки. Выполнение по шагам вызывает выполнение всего цикла for сразу, поэтому Вы не сможете видеть изменения в ходе выполнения цикла. Если же Вы хотите видеть подробности выполнения цикла, внесите в пример следующее простое изменение.

begin
  for I := 1 to 10 do
    WriteLn(Negate(I));
end.

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

Трассировка программы

Трассировка программы во многом аналогична ее выполнению по шагам. Единственное исключение состоит в том, что когда встречается оператор вызова процедуры/функции, при трассировке эти процедуры и функции также выполняются по шагам, а при простом выполнении по шагам управление возвращается вам после завершения выполнения подпрограммы.

Например, чтобы выполнить трассировку кода в вышеприведенном примере, загрузите файл, затем выберите команду Run → Trace Into или нажмите клавишу F7. Когда Вы в первый раз делаете это, управление перемещается на оператор begin основной программы. Повторное нажатие F7 снова перемещает строку управления на оператор for. После этого нажатие клавиши F7 трассирует вызов функции Negate — строка выполнения перемещается на оператор begin в блоке функции. Если Вы продолжаете нажимать F7, строка выполнения перемещается по функции, а затем, когда Вы дойдете до оператора end, возвращается к оператору вызова.

Формат программы влияет на поведение строки выполнения при трассировке, хотя и не в такой степени как при пошаговом выполнении. Если код сформатирован как в первоначальном варианте приведенного выше примера, то трассировка оператора for приводит к выполнению 10 раз функции Negate. Если вы разобьете оператор for на две строки, то трассировка оператора end функции возвращает строку выполнения: ту строку основной программы, которая будет выполняться следующей. Первые девять раз это снова будет вызов функции. В десятый раз строка выполнения перемещается на оператор end программы.

Трассировка или выполнение по шагам?

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

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

Пошаговое выполнение и трассировка методов объектов

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

Выполнение больших фрагментов

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

Чтобы задать в программе точку, до которой она должна выполняться, а затем остановиться, используйте команду Run → GoTo Cursor или клавишу F4. (Этим вы сообщите отладчику, что не хотите выполнять программу по шагам, пока не достигнете заданной точки.) Установите курсор на той строке, где вы хотите возобновить управление отладкой, затем нажмите клавишу F4. Заметим, что Вы можете сделать это как в начале сеанса отладки, так и когда уже выполните часть программы по шагам или протрассируете.

Внимание: С использованием этой команды связана одна особенность: если Вы хотите, чтобы программа выполнилась до определенной строки, и устанавливаете курсор внутри модуля (Unit), то этого не произойдет, Вы просто получите ошибку Cannot Run a Unit , и этим все закончится, т.к. IDE понимает это действие, как приказ запустить модуль, чего делать нельзя. Требуется объяснить IDE, чего Вы от нее хотите примерно так: «Запусти основную программу, и только потом выполни все, до текущего положения курсора». Для этого надо зайти в меню Compile → Primary File, указать системе основной файл (НЕ модуль) Вашего приложения, и
только после этого установить курсор внутрь модуля, и нажать F4

Казалось бы, что поменялось? А вот что: теперь IDE точно знает — основным
файлом приложения является тот, который был установлен, как Primary File,
следовательно, совершенно нет необходимости запускать МОДУЛЬ, достаточно
запустить основной файл, и остановиться тогда, когда выполнение дойдет до
нужной строки в модуле.

Что такое окно Watches и как им пользоваться?

Выполнение программы по шагам или ее трассировка могут помочь Вам найти ошибки в алгоритме программы, но обычно желательно также знать, что происходит на каждом шаге со значениями отдельных переменных. Можно, конечно, по-старинке добавлять в необходимые места программы оператор WriteLn, который распечатает значение контролируемой переменной (а иногда просто нет другого выбора, например, при компиляции крупных проектов на Турбо Паскале возникает необходимость вообще отказаться от IDE, и пользоваться автономной версией компилятора — TPC — запускаемой из командной строки), но если уж есть возможность пользоваться средой программирования — то лучше использовать для контроля за переменными одно из специальных средств IDE: окно Watches (Просмотр) или диалоговое окно Evaluate and Modify (Вычисление и модификация).

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

Элементы выражений отладчика

┌────────────────┬────────────────────────────────────────────────────┐
│Элемент         │Допустимые значения                                 │
│выражения       │                                                    │
├────────────────┼────────────────────────────────────────────────────┤
│                │Все допустимые типы: Boolean, Byte, Char,           │
│Константы       │перечислимый тип, Integer, Longint, Real, Shortint, │
│                │Word и строковый тип.                               │
├────────────────┼────────────────────────────────────────────────────┤
│Переменные      │Все типы, включая типы, определенные пользователем. │
├────────────────┼────────────────────────────────────────────────────┤
│   целочисленный│Любое целочисленное выражение с переменными         │
│тип             │границами диапазона.                                │
├────────────────┼────────────────────────────────────────────────────┤
│   тип с        │Любые выражения с плавающей точкой или целочисленные│
│плавающей точкой│выражения; лишние значащие цифры отбрасываются.     │
├────────────────┼────────────────────────────────────────────────────┤
│                │Любое символьное выражение, включая печатаемые      │
│   символьный   │символы в одинарных кавычках, целочисленные         │
│тип             │выражения, тип которых приведен к типу Char, и      │
│                │контанты ASCII (#xx).                               │
├────────────────┼────────────────────────────────────────────────────┤
│   булевский тип│True, False и все булевские выражения.              │
├────────────────┼────────────────────────────────────────────────────┤
│   перечислимый │Любые совместимые перечислимые константы или        │
│тип             │целочисленные выражения в рамках диапазона, тип     │
│                │которых приведен к совместимому перечислимому типу. │
├────────────────┼────────────────────────────────────────────────────┤
│                │Любые совместимые указатели или выражения с         │
│   указатель    │приведенными к ним типами; функция Ptr с            │
│                │соответствующим параметрами.                        │
├────────────────┼────────────────────────────────────────────────────┤
│                │Любая строковая константа (текст в одинарных        │
│   строковый тип│кавычках); строковые переменные; строковые          │
│                │выражения, состоящие из конкатенированных строковых │
│                │констант и переменных.                              │
├────────────────┼────────────────────────────────────────────────────┤
│                │Любая множественная константа; любое выражение,     │
│   множество    │совместимое с множественным типом, в котором        │
│                │используются операции +, - и *.                     │
├────────────────┼────────────────────────────────────────────────────┤
│Приведение типа │Соблюдаются стандартные правила Паскаля.            │
├────────────────┼────────────────────────────────────────────────────┤
│Операции        │Все операции Borland Pascal.                        │
├────────────────┼────────────────────────────────────────────────────┤
│Встроенные      │Все функции, допустимые в выражениях-константах.    │
│функции         │                                                    │
├────────────────┼────────────────────────────────────────────────────┤
│Массивы         │Массивы Borland Pascal - Mem, MemL, MemW.           │
└────────────────┴────────────────────────────────────────────────────┘

Разберем использование окна Watches

Вначале это окно нужно отобразить на экране. Делается это выбором пункта
меню Debug → Watch. На экране появится пустое окно с соответствующим заголовком.

Теперь запускаем программу в пошаговом режиме (нажатием клавиши F7, или
выбором меню «Run → Trace Into»), в редакторе устанавливаем курсор на
название переменной, за которой будем «следить», и жмем Ctrl+F7 (или меню
«Debug → Add Watch…») и подтверждаем выбор нажатием «Ok»… Всё…
Переменная добавлена в окно Watches, и можно наблюдать за ее значением на Watch каждом шаге выполнения программы…

Примечание: Если выбрать переменную для просмотра без предварительного
отображения пустого окна Watches на экране, ничего страшного не произойдет: IDE автоматически откроет окно Watches самостоятельно.

Например, после выполнения выделенной строки

i := 15;

значение переменной i будет уже равно не 0, а 15…

В окне Watches могут отображаться любые типы констант/переменных, объявленных в программе. Например, если описан массив …

const
  arr: array[1 .. 10] of integer = (
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10
  );

… то можно просмотреть одновременно (!!!) как весь этот массив, так
и его левую и правую части… Для этого достаточно ввести во втором и Просмотр третьем случае не только название массива, но и стартовый элемент, и массива (через запятую) число повторений.

Кроме массивов и переменных встроенных типов возможно просматривать Просмотр также и записи (либо в простом формате — только имя переменной, либо в записи специальном — с добавлением спецификатора R.

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

┌──────┬─────────────┬────────────────────────────────────────────────────────┐
│      │Тип, на      │                                                        │
│Символ│который он   │Функция                                                 │
│      │влияет       │                                                        │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│$, H  │целочисленные│Шестнадцатиричный. Выводит целочисленные значения с     │
│или X │типы         │префиксом $, включая те, которые содержатся в структуре │
│      │             │данных.                                                 │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│      │Char,        │Символьный. Выводит специальные символы для кодов ASCII │
│C     │строковые    │0..31. По умолчанию такие символы выводятся в виде      │
│      │типы         │значений #xx.                                           │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│      │целочисленные│Десятичный. Выводят целочисленные значения в десятичном │
│D     │типы         │виде (включая те, которые содержатся в структурах       │
│      │             │данных).                                                │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│Fn    │с плавающей  │С плавающей точкой. Выводит n значащих цифр, где n лежит│
│      │точкой       │в диапазоне 2..18 (по умолчанию - 11).                  │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│      │             │Дамп памяти. Выводит n байт памяти, начиная с адреса,   │
│nM    │все          │указываемого выражением. Если n не задано, то по        │
│      │             │умолчанию оно равно значению размера в байтах типа      │
│      │             │переменной.                                             │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│P     │указатели    │Указатель. Выводит указатели в формате сегм:смещ (а не  │
│      │             │Ptr(сегм:смещ), как это делается по умолчанию.          │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│R     │записи,      │Запись. Выводит имена полей, например, (X:1;Y:10; Z:5)  │
│      │объекты      │вместо (1, 10,5).                                       │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│      │             │Строки. Выводит символы ASCII 0..31 в виде #xx.         │
│S     │Char, строки │Использует только для модификации дампов памяти (см.    │
│      │             │выше nM).                                               │
└──────┴─────────────┴────────────────────────────────────────────────────────┘

Окно Evaluate and Modify

Но кроме простого просмотра значений той или иной переменной или выражения,
существует средство, позволяющее вам в любой момент вычислять выражения и
изменять на этапе выполнения значения переменных. Этим средством и является
диалог Evaluate and Modify (Вычисление и модификация).

Вычисление выражений

Чтобы вычислить выражение, выбираем команду Debug → Evaluate/Modify или нажимаем клавиши Ctrl+F4. Отладчик выводит диалоговое окно Evaluate and Modify (Вычисление и модификация). Здесь (в поле ввода Expression) можно занести любое допустимое выражение , или выбрать его из списка ранее вычисленных при помощи этого же диалога выражений и отредактировать.

После нажатия на Enter или щелчка мышью на кнопке Evaluate (Вычислить), текущее значение выражения будет показано в поле Result (Результат).

Примечание: если в поле Expression введено выражение, которое не может быть вычислено интегрированной средой, то в поле Result появится вот такая надпись: «Cannot evaluate this expression».

Модификация переменных

Кроме этого, во время отладки с помощью диалогового окна Evaluate and Modify существует возможность поменять значение переменной на любое другое, чтобы проверить работу программы с другим, вновь присвоенным значением переменной. Для этого нужно установить курсор на имени переменной, и выбрать в меню Debug → Evaluate/Modify… (или просто нажать Ctrl+F4)…

В появившемся окне в поле Expression (Выражение) достаточно ввести имя переменной (или ничего не делать, если имя уже введено), и нажать кнопку Evaluate… Текущее значение выбранной переменной будет отображено в поле Result. Если оно же отображается и в поле New Value, это значит, что у Вас есть возможность прямо сейчас поменять это значение на любое другое (разумеется, совместимое по присваиванию с типом выбранной переменной; присваивать строке целому числу Вам никто не позволит, также, как и, например, записать в целочисленную переменную значение 3.14159), и применить новое значение переменной, не перезапуская программу…

Например, допустим, что программа имеет вид:

var
  i: integer;
begin
  for i := 1 to 20 do
    writeln(i);
  readln;    
end.

, и Вам захотелось попасть в точку, где распечатывается значение i = 20 (желание далеко не самое сумасшедшее, представьте, например, что вместо простого распечатывания значения i там будет вызов какой-нибудь функции, которую надо прогнать пошагово при определенном значении i, да еще и функция может быть длинной и долго выполняться), но не очень хочется нажимать F7 почти 20 раз и приходить в нужную точку «естественным путем». Что делаем? А вот что:

Добавляем значение i в окно Watches, начинаем выполнять программу пошагово (F7)… Я остановился, когда значение i было равно трем, хотя это же самое можно было сделать и сразу после входа в цикл, то есть как только i стало равно единице.

Теперь ставим курсор под название переменной i и жмем Ctrl+F4 для вызова нужного нам окна… Состояние экрана, которое должно получиться, видно на скриншоте…

Переходим в поле New Value (как я говорил, если в нем записано текущее значение переменной, то нам будет позволено его сменить), печатаем в нем значение 20, и жмем на «Modify»…

Как видим, значение i в Watches тоже поменялось на 20, теперь спокойно закрываем окно «Evaluate and Modify» (кнопкой Cancel), и продожлжаем выполнять программу пошагово…

Таким образом, мы пропустили все НЕинтересующие нас в данном случае шаги,
выполнение которых могло занять значительное время…

Окно Call Stack — что это такое?

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

Да и не нужно этого держать в голове. Для этого существует такое средство, как «Call Stack» (вызывается из меню Debug → Call Stack или просто Ctrl+F3). Например, пусть наша программа имеет вид:

function fact(n: longint): longint;
begin
  if n = 0 then fact := 1
  else fact := n * fact(n - 1);
end;
 
function b(n: longint): integer;
begin
  b := 2 * fact(n);
end;
 
begin
  writeln( b(10) );
end.

Если начать выполнять ее пошагово, очень скоро можно запутаться в том, что именно сейчас выполняется (факториал какого числа вычисляется в данный момент, к примеру), и что еще осталось НЕзавершенным. А если программа будет в 10 раз длиннее, и будет содержать не 2, а 10 процедур/функций? В таком случае достаточно вызвать окно Call Stack (способ вызова — выше), и посмотреть, что именно в данный момент выполняется (то есть находится на першине стека вызовов), и что еще выполняться будет (находится ниже в списке), вплоть до Program, обозначающего, самый нижний уровень — основную программу…

Вот, например, в данном случае: выполняется функция вычисление факториала 8, которая вызвана из нижестоящей в списке функции вычисления факториала 9, которая в свою очередь… Ну, дальше все понятно… При продолжении пошагового выполнения этой программы в окно Call Stack будут добавляться новые и новые вызовы Fact (7), Fact(6), … до Fact(0); потом рекурсия начнет раскручиваться обратно…

Кстати, Call Stack — незаменимый помощник именно при работе с рекурсивными подпрограммами, поскольку дает возможность контролировать последовательность вызовов рекурсивной функции, и на ранней стадии определить, например, бесконечную рекурсию…
Например, здесь — совершенно очевидно, что рекурсивная функция оформлена неверно (отсутствует ветка Else), сразу после того, как в окне Call Stack появились вызовы f (-1) и f(-2)…

Еще одно полезное применение окна Call Stack — если вы случайно начали трассировку кода, который хотели бы выполнить за один шаг. В стеке вызовов вы можете найти тот вызов, который начали трассировать по ошибке, затем выбрать команду Run to Cursor, чтобы выполнить за один шаг остальную часть вызова.

Что такое точки останова программы?

Кроме всех вышеперечисленных возможностей, значительно облегчающих жизнь программисту, в IDE Паскаля встроено еще одно средство, очень мощное и эффективное (при правильном использовании)… Это — работа с точками останова программы (BreakPoints).

Точка останова — это обозначенная в коде программы позиция, в которой вы хотите прекратить выполнение программы и вернуть выполнение отладчику. В этом смысле точка останова работает аналогично команде GoTo Cursor, при которой программа выполняется обычным путем до достижения определенной точки. Основное различие состоит в том, что вы можете задать несколько точек останова и точки останова, которые будут срабатывать не при каждом их достижении.

Допустим, есть следующая программа:

const
  parameter = 10;
 
function f(x: integer): integer;
begin
  f := 10 * parameter - sqr(x);
end;
 
var
  i, j: integer;
  arr: array[1 .. 20] of real;
begin
  for i := 1 to 20 do begin
    j := f(i);
    arr[i] := (15 * j / parameter) + i / j - 8;
  end;
  { ... }
end.

(не обольщайтесь, программа может быть не в 17, а в 1700 строк длиной, и функция f может быть гораздо более сложной, так же как и способ ее вызова)…

Естественно, запустив эту программу, получаем:

Runtime error 200 at 0006:0004.

, из чего заключаем, что где-то в программе происходит деление на 0. Ну, где
оно происходит, понятно. А вот на какой итерации? Чему равно i, при котором
происходит эта ошибка? Можно, конечно, воспользоваться старым и проверенным
способом, и сделать так:

const
  parameter = 10;
 
function f(x: integer): integer;
begin
  f := 10 * parameter - sqr(x);
end;
 
var
  i, j: integer;
  arr: array[1 .. 20] of real;
begin
  for i := 1 to 20 do begin
    j := f(i);
    writeln('j = ', j);
    arr[i] := (15 * j / parameter) + i / j - 8;
  end;
  { ... }
end.

, после чего нам будут распечатаны все значения j, для которых программа отработала нормально, и еще одно, при котором как раз и произошло «Деление на Ноль». Но для этого нужно вносить изменения в программу. А можно обойтись без её изменений… Используя точку останова…

Для этого проделаем следующее… Во-первых, добавим переменную i в список Watches, так как нам нужно найти именно «при каком i программа вылетает».

Далее — установим курсор на той строке программы, где происходит деление, и выберем в меню пункт «Debug → Add Breakpoint…» Экран примет вид, показанный на снимке справа.

Примечание: строка, на которую устанавливается BreakPoint, должна содержать выполняемый код и не может быть комментарием, описанием или пустой строкой…

В поле Condition внесем условие, при котором следует остановить программу (условие вводится так же как и при использовании условных операторов в программе, только Условный If здесь присутствовать не должно), и подтверждаем установку BreakPoint-а нажатием кнопки «Ok»:

Строка, в которой установлен хотя бы один BreakPoint (а устанавливать можно несколько точек останова для программы, причем даже на одной строке, но с разными условиями, может быть установлено более одного BreakPoint-а) меняет цвет на красный…

Если теперь запустить программу (обычным способом — через Ctrl+F9, или пошагово, не имеет значения), то как только значение j в Условный выделенной строке станет равным 0, прогон программы будет приостановлен с выдачей вот такого сообщения:

Как видим (в окне Watches), происходит это при i = 10… Что и требовалось
определить…

Чтобы просмотреть, какие BreakPoint-ы были установлены в программе, достаточно зайти в меню «Debug → BreakPoints», и будет выведен список всех точек останова для данной программы:

Нажатием на «Clear All» можно удалить все точки останова сразу, «Delete» удалит только подсвеченный BreakPoint, а «Edit»-ом можно отредактировать текущий (подсвеченный) BreakPoint — подкорректировать условие, поменять номер строки, в которой должна производиться проверка, изменить счетчик числа проходов (задание для точки останова счетчика проходов сообщает отладчику, что останавливать программу нужно не при каждом достижении точки останова, а только на n-ый раз. То есть, если счетчик проходов равен 3, то отладчик останавливает программу только при третьем достижении данной точки останова) и т.д.

Поиск нужного места

IDE предусматривает два способа поиска в программе заданного места. Простейший способ предоставляет команда Find Procedure (Поиск процедуры) из меню Search. Эта команда запрашивает у Вас имя процедуры или функции, затем находит соответствующую строку в файле, где определяется эта подпрограмма. Этот подход полезно использовать при редактировании, но его можно комбинировать с возможностью выполнения программы до определенной точки, чтобы пройти программу до той части кода, которую вы хотите отладить.

Повторное выполнение (сброс программы)

В ходе сеанса отладки иногда желательно начать все сначала. Выберите команду Run → Reset Program или нажмите клавиши Ctrl+F2. Это приведет к полному сбросу, так что выполнение по шагам, или трассировка начнется в начале основной программы.

Отслеживание вывода программы

При выполнении программы по шагам часто полезно просмотреть вывод программы, называемый экраном пользователя. IDE предоставляет несколько способов просмотра экрана пользователя.

Переключение экранов

В любой момент сеанса отладки вы можете выполнять переключение экрана IDE и экрана пользователя. Чтобы вывести экран пользователя, нажмите клавиши Alt+F5. Чтобы вернуться в IDE, нажмите любую клавишу или щелкните «мышью».

Окно Output

IDE для DOS предусматривает для экрана пользователя окно, которое называется окном вывода. Выбрав команду меню Debug → Output, вы можете открыть (вывести на передний план) активное окно, содержащее вывод программы. Настроить размер этого окна можно аналогично окну редактирования.

Добавил:

Upload

Опубликованный материал нарушает ваши авторские права? Сообщите нам.

Вуз:

Предмет:

Файл:

Pascal.doc

Скачиваний:

26

Добавлен:

12.03.2016

Размер:

3.29 Mб

Скачать

Сообщения
об ошибках.
Ошибки в
программах делятся на те, которые
Паскаль замечает, и на те, что не замечает
и в принципе заметить не может. К первым
относятся все синтаксические погрешности,
например,BIGINвместоBEGIN.
Их Паскаль замечает еще на стадии
компиляции. На стадии выполнения он
замечает такие ошибки, какSqrt(-25),
то есть квадратный корень из ‑25. Но
вот, если вы, желая возвести числоa
в куб, вместоa*a*aпишетеa*a,
то этого не заметит ни один язык в мире.

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

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

Вот наиболее
типичные для начинающих сообщения об
ошибках того и другого рода:

Сообщение

Перевод

Вероятная
причина ошибки

Unexpected end of file

Неожиданный
конец файла

Вы забыли
поставить точку после последнего
END.
Или не совпадает количествоbeginи количествоend

“;” expected

Ждал точку с
запятой

Вы забыли
поставить точку с запятой после
предыдущего оператора

“,” expected

Ждал запятую

Вы указали
слишком мало параметров в обращении
к подпрограмме

“)” expected

Ждал скобку “)”

Вы указали
слишком много параметров в обращении
к подпрограмме

Unknown identifier

Неизвестное
имя

Вы забыли описать
это имя в разделе описаний

Неправильно
записали стандартное имя, например,
ReedLnвместоReadLn

Type mismatch

Несовпадение
типов

В вашей программе
встречаются примерно такие «сладкие
парочки»: VAR c:String; … c:=1+2илиVAR
h:Integer; … h:=9/7

Duplicate identifier

Дубль имени

Одно и то же имя
описано два раза. Например,
VAR a, c, a :String;

Syntax error

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

Паскаль
затрудняется назвать причину ошибки.
Часто причина в том, что вы забыли
взять строковую константу в кавычки

BEGIN
expected

Ждал BEGIN

Возможно, не
совпадает количество beginи количествоend

END
expected

Ждал
END

Возможно, не
совпадает количество beginи количествоend

String
constant exeeds line

Строковая
константа превышает допустимую длину

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

Line too long

Строчка слишком
длинна

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

Disk full

Диск заполнен

На вашем диске
не осталось места. Надо что-то стереть

Lower bound greater than
upper bound

Нижняя граница
диапазона больше верхней

Например, вы
вместо array[2..5]написалиarray[5..2].

Invalid floating point
operation

Неправильная
операция с вещественным результатом

Sqrt(-25)илиa/0или что-нибудь в этом роде

Ordinal expression
expected

Ждал выражение
порядкового типа

Например, вы
вместо for
i:=1
to
8
написали
for
i:=1
to
8.5

Error in expression

Ошибка в выражении

Например, вы
вместо k:=а*8написалиk:=а**8

Range check error

Ошибка проверки
диапазона

Переменная
в процессе выполнения программы
вышла за пределы допустимого диапазона,
как например, в 1.9

Constant out of range

Константа не в
диапазоне

Величина
константы в программе превосходит
допустимый диапазон

Invalid numeric format

Неправильный
числовой формат

Если, например,
вы по оператору ReadLn(k)в программеVAR
k:Integer; …. ReadLn(k) …
пытаетесь
ввести число 25.3

Более подробное
описание некоторых ошибок вы найдете
в 0.3.

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

expected
ждал

identifier
имя

invalid
неправильный

operation операция

error
ошибка

variable переменная

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

![введите сюда описание изображения]1

с шестой строки выдает ошибку, хотя пишу с учебника, в чем проблема?
Паскаль абсNET. Использование вещественных числе с целыми.

b:=n; writeln ('b=',b);
n:=trunk(a);writeln ('trunk'(3.6)=',n);

Anton Shchyrov's user avatar

Anton Shchyrov

33k2 золотых знака29 серебряных знаков59 бронзовых знаков

задан 1 дек 2016 в 13:10

GProst's user avatar

11

После третьей строки должен быть begin, на 7 строке второй апостроф — лишний.

A K's user avatar

A K

28.4k19 золотых знаков54 серебряных знака130 бронзовых знаков

ответ дан 1 дек 2016 в 13:21

Anton Shchyrov's user avatar

Anton ShchyrovAnton Shchyrov

33k2 золотых знака29 серебряных знаков59 бронзовых знаков

3

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

  1. Создайте пустую программу
  2. Запустите — запустилось — хорошо, не запустилось ищите ошибку.
  3. Добавляйте по одной строчке из вашего примера и запускайте — таким образом вы увидите какую строку перепечатали неверно!

ответ дан 1 дек 2016 в 13:23

JVic's user avatar

JVicJVic

3,2691 золотой знак15 серебряных знаков35 бронзовых знаков

1

Паскаль
— это один из самых простых языков, но
далеко не один из самых слабых. Изучать
мы с вами будем Turbo
Pascal 7.0

так вот на нем можно написать любую
программу, которая придет в голову. По
возможностям он не уступает ни СИ, ни
какому другому. На Паскале можно написать
программную оболочку (типа Norton Commander),
игрушку (типа Quake) или операционную
систему (типа MS-DOS). Программы на Turbo
Pascal пишутся только для платформы MS-DOS,
но никак не зависят от конфигурации
компьютера. Главным требованием к
компьютеру является только лишь то,
чтобы он был IBM PC-совместимый, что
естественно, если на нем установлен
MS-DOS.

Особой
теории по этому языку нет, чтобы хорошо
им овладеть (тем более если это ваш
первый язык программирования) необходимо
больше практики. Этим мы и начнем
заниматься уже в этом выпуске. При этом
вам понадобиться интерпритатор Turbo
Pascal 7.0
фирмы
Borland — я говорил где его можно достать в
предыдущем выпуске. Те, кто скачал его
с моего сайта (а скачало на данный момент
73 человека) или достал где-нибудь еще,
уже смогут попрактиковаться.

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

Итак,
поехали…

Ваша
первая программа на Паскале.

Что
ж, начнем с минимума. Предположим, что
вам понадобилось написать программу,
реализующую сложение двух чисел. Короче,
надо сделать C
= A + B;

Теперь
по шагам определим, что необходимо для
создания этой программы.

1.
Нам необходимо в некоторое число C
занести
значение, которое будет равно сумме
чисел А
и
В.
Для таких целей в Паскале существует
понятие переменной.
(Это вроде икса в математике). Переменная
служит для хранения какого-либо значения
и имеет собственное имя. Это имя ей
необходимо назначить — оно может состоять
только из:

  1. латинских
    букв (A..Z);

  2. цифр
    (0..9)
    (!!! но не может начинаться с цифры !!!);

  3. символов
    подчеркивая «_«;

И
не может содержать:

  1. Русских
    букв;

  2. Любых
    знаков препинания, таких как точка,
    запятая, восклиц. знак;

  3. Специальных
    символов, которые находятся над цифрами
    на клавиатуре. Это «~», «#», «$»,
    «%» и другие.

Вот
вам примеры имен переменных:

primer1;
_primer; Primer; _pr_; my_name_is_Edik;

Еще
уточнение — имя переменной может быть
любой длины, не превышающей 250 символов.
Также не учитывается регистр букв, то
есть переменные с именами Primer
и pRiMeR
будут рассматриваться как одна.

Что
у нас выходит? Что нам необходимо завести
переменные С, А, В. (Не забывайте, все
буквы латинские). Ясно, переменные мы
заведем и назначим им имя (как мы это
сделаем, смотрите ниже). Что теперь? А
теперь мы подходим к понятию типа
переменной
.

Тип
переменной

определяет, что с этой переменной можно
сделать, и из чего она состоит (что в ней
содержится). Для каждой переменной
определяется ее тип.

Зачем
нам нужно определять тип переменной?
Например, нам нужно, чтобы переменная
содержала строку символов, к примеру
«Здравствуйте!»,
которую мы хотим вывести на экран в
качестве приветсвия. И кроме нее мы
имеем переменную, содержащую число,
которое мы собираемся увеличивать.
Понятно, что мы не сможем сложить число
со строкой, так как цифры с символами
складывать невозможно. Поэтому мы
определяем тип этой переменной как
числовой, после чего определяем тип
переменной, содержащей строку как
строковой. Тогда Паскаль будет знать,
что с какой переменной можно сделать,
и при произведении каких-либо действий
с переменными определять их тип, после
чего либо производить действия, либо
нет, если их произвести невозможно.

В
общем, я сказал, что у каждой переменной
есть свой тип. Но как его назначить? Для
этого существуют разные обозначения.
Например, тип «число» обозначается
как Integer,
что по-английски означает «число».
Зная это, мы в программе указываем, что
переменная у нас типа Integer
и можем ее складывать с другими, вычитать
или умножать. (О других типах я расскажу
позже).

2.
Итак, с типами переменных мы определились
и теперь возвращаемся к нашей с вами
программе. Что у нас там? Мы собираемся
прибавить к переменной A
переменную B
и поместить результат в переменную С.

Так
как я сказал, что складывать можно только
переменные типа Integer,
то нам необходимо определить тип всех
трех переменных как Integer.
Сделав это, мы получим возможность
манипулировать ими как числами.

Исходя
из всего этого напишем программу, в
которой реализуем следующие шаги:

  1. Напишем
    название программы;

  2. Заведем
    переменные, т.е. A, B, C; и зададим им тип;

  3. Выполним
    сложение и пометим результат в С;

Программа
будет выглядеть следующим образом:

Program
First;

var

A,
B, C: Integer;

begin

C
:= A + B;

end.

Теперь
разберем эту программу по строкам:

  1. Program
    First
    ;
    — это заголовок программы. Совсем
    необязательный, программисты просто
    пишут его для того, чтобы как-то озаглавить
    программу. Его хорошо использовать для
    маркировки, т.е. чтобы по нему определять,
    что это за программа. Всегда находится
    в первой строчке программы, если его
    разместить где-нибудь в другом месте,
    то это вызовет ошибку.

  2. var

    A, B, C: Integer;
    var

    — Это и есть раздел описания переменных.
    Выше я говорил, что надо заводить
    необходимые переменные и придавать им
    определенный тип. Вот здесь это и
    реализуется. После служебного слова
    var,
    сообщающего Паскалю, что начался раздел
    объявления переменных, надо расставить
    все переменные, и через двоеточие
    указать их тип. Я говорил, что числа
    указываются словом Integer.
    Вот мы и написали: A,B,C:
    Integer
    ;

  3. begin
    — это служебное слово означает, что
    начался раздел действий. Именно после
    него программа начинает свое выполнение.
    По-английски «begin» — значит «начало».
    Когда Паскаль встречает это слово, он
    начинает выполнение программы. У слова
    begin
    есть завершающая пара — end.
    Его вы можете увидеть в самом конце
    программы. Это слово совершенно
    противоположное по значению — то есть
    оно означает, что выполнение программы
    закончилось. Именно пара begin
    — end
    .
    и есть главной в программе, между ней
    находятся все действия.

  4. C
    := A + B
    ;
    Это и есть то, что нам необходимо было
    сделать. Здесь все ясно, но думаю
    синтаксис этого выражения требует
    пояснений. Но это все далее, смотрите…

Синтаксис
выражений.

Самое
главное правило — после каждой команды
или выражения ставится точка с запятой
— «;» Посмотрите на программу — каждая
строка имеет свое завершение этим
знаком. Исключение составляют только
слова var
и begin
— это служебные слова, которые не являются
процедурами или функциями. Они определяют
начало какого-либо раздела программы,
в частности var
— начало раздела объявления переменных,
а begin
— раздела выполнения. Кроме этих служебных
слов есть и другие, которые оглавляют
разделы, например начало раздела
констант, но об этом позже. Завершение
имеет только раздел begin
словом end,
после которого ставиться точка. Точка
означает конец программы, ее завершение
и полную остановку выполнения.

Кроме
того, присваивание в Паскале обозначается
знаком «:=»; Именно двоеточие и
равно, а не просто равно. То есть, если
мы хотим присвоить какой-либо переменной
значение, то мы пишет эту переменную,
ставим «:=» и пишем новое ее значение.
Вот вам еще примеры присваиваний, как
дополнение к программе:

C
:= 15;

A
:= 15 + 3;

A
:= A + C + 3 — 12;

Отсюда
имеет несколько правил синтаксиса,
которые сведем в список:

  1. После
    выражений ставиться «;»

  2. Служебные
    слова, означающие начало раздела
    программы, не оканчиваются знаком «;»

  3. Присваивание
    значения переменной обозначается
    знаком «:=»

Тестирование
программы.

Теперь
вернемся к программе. Запустите Turbo
Pascal и напечатайте ее, соблюдая все знаки
и порядок строк. После того, как вы ее
напечатали, надо попробовать ее запустить.
Это реализуется нажатием клавиш Ctrl+F9.
Если вы все правильно набрали, то окно
редактора чуть-чуть мигнет (или нет,
если у вас быстрый компьютер и вы просто
не успеваете этого заметить).

Если
вы в чем-то ошиблись, то Паскаль не
выполнит программу, а остановится,
переместив курсор в строку, где совершена
ошибка, и написав, что конкретно за
ошибка произошла. К примеру, таким
сообщением может быть:

Error
85: «;» expected.

Эта
ошибка означает, что вы где-то забыли
поставить «;». Но пока я не советую
вам самостоятельно разбираться в
ошибках, просто перепечатайте программу
в том виде, в каком она есть и все. Далее
мы будем этим заниматься (разбором
ошибок) — но это уже потом.

Что
теперь?

А
теперь, вроде все. Мы написали с вами
минимальную программу, которая тем не
менее уже хоть как-то демонстрирует
внешний вид программы. Она еще не живая,
я хочу сказать, что она не просит ни
каких данных у пользователя, и не выводит
ему ответ на них. Можно было бы сделать,
например, чтобы запрашивалось A и В, а С
(сумма) выводилась в ответ на экран. Вы
уже смогли попробовать среду Турбо
Паскаля, запустить программу и понять,
что это такое. Теперь я хочу заострить
внимание на том, что вам необходимо
усвоить из этого выпуска:

  1. Вам
    необходимо полностью разобраться в
    каждой строчке написанной программы;

  2. Усвоить
    основные правила синтаксиса («;»,
    :=, begin-end, var и т.д.
    );

  3. Понять,
    что необхоимо заводить переменные и
    как это делать;

  4. Понять,
    что такое тип переменной, как ее сделать
    числом и зачем это нужно;

  5. Обратить
    внимание на то, как мы запустили программу
    (Ctrl+F9); (Далее
    я буду подробнее рассказывать о таких
    клавишах)

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

Когда
вы запускаете эту программу, то видите
синее окно ввода. Именно в нем и набирается
текст программы — вы вводите ее с
клавиатуры. Вверху находиться полоса
меню, через нее осуществляется доступ
ко всем ресурсам и возможностям Турбо
Паскаля. Активным меню становиться при
нажатии клавиши F10. Основные взможности
меню, о которых я хочу вам рассказать —
это Открытие и Сохранение файлов.

Представим,
что мы начали писать в окне ввода
программу, которую не закончили, и хотим
дописать после. Что надо сделать?
Сохранить ее на диске, а после загрузить
обратно в редактор.

Итак,
запускаем Паскаль и набираем что-нибудь
в онке редактора. Далее — сохраняем
программу. Для этого:

  1. Нажимаем
    F10
    и переходим в меню.

  2. Выбираем
    меню File,
    а далее — Save
    — открывается окно сохранения файла.

  3. Выбираем
    имя для файла и вводим его в строку
    ввода.

  4. Нажимаем
    Enter
    и файл сохраняется.

Теперь
можно выйти из программы.

Как
загрузить файл обратно в Паскаль?
Программы на Паскале всегда имеют
расширение .pas. Зная это, мы всегда будем
безошибочно отличать их от других
файлов.

Открываем
файл в Паскале:

  1. Запускаем
    Turbo Pascal и нажимаем F10.

  2. Выбираем
    меню File,
    после Open.
    Появляется окно открытия файла.

  3. Вводим
    имя файла в строку ввода или выбираем
    его из списка.

  4. Нажимаем
    Enter
    и Паскаль открывает окно редактора с
    текстом программы, сохраненной на
    диске.

Вот
и все действия, необходимые для того,
чтобы успешно использовать сохранение
и загрузку программ. Но кроме этого,
программы необходимо запускать и
проверять на ошибки. Эти действия тоже
осуществляются через меню, но можно
также использовать «горячие клавиши»
— сочетания клавиш, при которых быстро
производиться доступ к пунктам меню,
без перехода к нему и соответсвующего
выбора.

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

Проверка на ошибки — «компиляция».

Имея
в окне редактора текст программы, можно
проверить его на ошибки — такие как
ошибки синтаксиса (забыли поставить
«;»), ошибки в служебных словах
(написали не begin, a bigin) и другие.

Для
того, чтобы это сделать, необходимо
нажать клавиши Alt-F9:
нажать Alt
и удерживая его нажать F9.

После
этого начнется процесс проверки и если
все написано без ошибок, то появиться
окно успешной компиляции, в котором
будет мигать надпись

«Compile
successfull: Press any key»

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

Процесс,
который поисходит при этом, называется
«компиляция».

Компиляция
— это перевод программы с языка
программирования на язык машинный,
понятный компьютеру.

При
нажатии сочетания клавиш Alt-F9
и происходит попытка компиляции, то
есть ваша программа переводиться с
Паскаля на машинный язык. И если этот
процесс не будет прерван ошибками в
синтаксисе, структуре или какими-либо
еще, то программа может быть запущена
и выполнена компьютером.

Как
это сделать — запустить программу?
Читайте…

Содержание

Отладка программ в Turbo Pascal

Автор: volvo877 (он же и volvo71)

Ссылка на оригинал статьи

FIXME (не хватает картинок из статьи)

Каждый программист знает, что программу надо не только написать, иначе говоря —
«заставить работать», а еще и отладить, т.е. заставить ее работать правильно…
Для того, чтобы делать это быстро и эффективно, желательно научиться
пользоваться встроенными в IDE средствами отладки программ…

Интегрированная интерактивная среда разработки программ Borland Pascal (IDE)
включает в себя ряд средств, облегчающих разработку программ: автоматическое
управление проектами, средств обеспечения модульной структуры программы,
быструю компиляцию и простые в использовании оверлеи. Но, несмотря на все это,
Ваша программа все равно может содержать ошибки, что не позволит ей корректно
работать.

IDE для DOS Borland Pascal предоставляет вам инструментальные средства для
отладки программ, то есть поиска и исправления ошибок. В этой статье
описываются инструментальные средства и процедуры отладки программы в
интегрированной среде Борланд Паскаль (большинство описанных возможностей
применимо также к IDE FreePascal-я).

Что такое отладка?

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

Какие существуют виды ошибок?

Существует три основных типа ошибок:

  • Ошибки этапа компиляции

  • Ошибки этапа выполнения

  • Логические ошибки

Ошибки этапа компиляции

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

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

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

Ошибки этапа выполнения

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

Когда такая ошибка обнаруживается, выполнение программы завершается, и выводится сообщение следующего вида:

Run-time error ## at seg:ofs

Если Вы выполняете программу из IDE, она автоматически находит оператор,
вызвавший ошибку (как и в случае синтаксических ошибок). Если же программа выполняется вне IDE (EXE-файл запускается из командной строки или файлового менеджера ОС), то вы можете запустить IDE и, чтобы найти вызвавший ошибку оператор, использовать команду Search → Find Error, которая дает вам адрес сегмента и смещения (seg:ofs).

Логические ошибки

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

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

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

Пошаговый прогон: какая разница между F4, F7 и F8?

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

  • Выполнять инструкции по шагам

  • Трассировать инструкции

  • Выполнять программу до заданной точки

  • Находить определенную точку

  • Выполнять сброс программы

Само по себе выполнение программы по шагам может быть недостаточно полезным, разве что поможет найти то место, где что-то происходит совершенно неверно. Но управляемое выполнение дает Вам возможность проверять состояние программы и ее данных, например, отслеживать вывод программы и ее переменные.

Что такое шаг?

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

Все выполнение в отладчике, включая выполнение по шагам, трассировку и останов, основывается на строках. Подсвечивая строку, встроенный отладчик всегда сообщает Вам, какую строку он выполнит на следующем шаге (строка выполнения). Строка выполнения выводится цветом, отличным от нормального цвета. Благодаря этому Вы можете легко видеть, где находитесь.

Выполнение программы по шагам

Выполнение по шагам — это простейший способ выполнения программы по
элементарным фрагментам. Выбор команды Run → Step Over или нажатие клавиши F8 вызывает выполнение отладчиком всего кода в операторе, указанном строкой выполнения, включая любые вызываемые на ней процедуры или функции, пока управление не вернется обратно к вам. После этого строка выполнения указывает следующий выполняемый оператор.

Возьмем, например, следующую программу:

program StepTest;
 
  function Negate(X: Integer): Integer;
  begin
    Negate := -X;
  end;
 
var
  I: Integer;
begin
  for I := 1 to 10 do Writeln(Negate(I));
end.

Если в окне редактирования Вы выведете StepTest и нажмете клавишу F8, то строка выполнения перемещается на оператор begin в начале основного цикла, поскольку это первое, что выполняется в программе. Второе нажатие клавиши F8 выполняет begin и перемещает строку выполнения вниз до оператора for на следующей строке.

После этого нажатие F8 вызывает выполнение всего цикла for; на экран
пользователя выводятся числа от -1 до -10, а строка выполнения перемещается к end.

Хотя функция Negate и вызывается 10 раз, строка выполнения никогда на нее не перемещается. Выполнение по шагам позволяет отладчику не показывать детали любых вызовов для отдельной строки. Выполнение по шагам вызывает выполнение всего цикла for сразу, поэтому Вы не сможете видеть изменения в ходе выполнения цикла. Если же Вы хотите видеть подробности выполнения цикла, внесите в пример следующее простое изменение.

begin
  for I := 1 to 10 do
    WriteLn(Negate(I));
end.

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

Трассировка программы

Трассировка программы во многом аналогична ее выполнению по шагам. Единственное исключение состоит в том, что когда встречается оператор вызова процедуры/функции, при трассировке эти процедуры и функции также выполняются по шагам, а при простом выполнении по шагам управление возвращается вам после завершения выполнения подпрограммы.

Например, чтобы выполнить трассировку кода в вышеприведенном примере, загрузите файл, затем выберите команду Run → Trace Into или нажмите клавишу F7. Когда Вы в первый раз делаете это, управление перемещается на оператор begin основной программы. Повторное нажатие F7 снова перемещает строку управления на оператор for. После этого нажатие клавиши F7 трассирует вызов функции Negate — строка выполнения перемещается на оператор begin в блоке функции. Если Вы продолжаете нажимать F7, строка выполнения перемещается по функции, а затем, когда Вы дойдете до оператора end, возвращается к оператору вызова.

Формат программы влияет на поведение строки выполнения при трассировке, хотя и не в такой степени как при пошаговом выполнении. Если код сформатирован как в первоначальном варианте приведенного выше примера, то трассировка оператора for приводит к выполнению 10 раз функции Negate. Если вы разобьете оператор for на две строки, то трассировка оператора end функции возвращает строку выполнения: ту строку основной программы, которая будет выполняться следующей. Первые девять раз это снова будет вызов функции. В десятый раз строка выполнения перемещается на оператор end программы.

Трассировка или выполнение по шагам?

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

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

Пошаговое выполнение и трассировка методов объектов

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

Выполнение больших фрагментов

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

Чтобы задать в программе точку, до которой она должна выполняться, а затем остановиться, используйте команду Run → GoTo Cursor или клавишу F4. (Этим вы сообщите отладчику, что не хотите выполнять программу по шагам, пока не достигнете заданной точки.) Установите курсор на той строке, где вы хотите возобновить управление отладкой, затем нажмите клавишу F4. Заметим, что Вы можете сделать это как в начале сеанса отладки, так и когда уже выполните часть программы по шагам или протрассируете.

Внимание: С использованием этой команды связана одна особенность: если Вы хотите, чтобы программа выполнилась до определенной строки, и устанавливаете курсор внутри модуля (Unit), то этого не произойдет, Вы просто получите ошибку Cannot Run a Unit , и этим все закончится, т.к. IDE понимает это действие, как приказ запустить модуль, чего делать нельзя. Требуется объяснить IDE, чего Вы от нее хотите примерно так: «Запусти основную программу, и только потом выполни все, до текущего положения курсора». Для этого надо зайти в меню Compile → Primary File, указать системе основной файл (НЕ модуль) Вашего приложения, и
только после этого установить курсор внутрь модуля, и нажать F4

Казалось бы, что поменялось? А вот что: теперь IDE точно знает — основным
файлом приложения является тот, который был установлен, как Primary File,
следовательно, совершенно нет необходимости запускать МОДУЛЬ, достаточно
запустить основной файл, и остановиться тогда, когда выполнение дойдет до
нужной строки в модуле.

Что такое окно Watches и как им пользоваться?

Выполнение программы по шагам или ее трассировка могут помочь Вам найти ошибки в алгоритме программы, но обычно желательно также знать, что происходит на каждом шаге со значениями отдельных переменных. Можно, конечно, по-старинке добавлять в необходимые места программы оператор WriteLn, который распечатает значение контролируемой переменной (а иногда просто нет другого выбора, например, при компиляции крупных проектов на Турбо Паскале возникает необходимость вообще отказаться от IDE, и пользоваться автономной версией компилятора — TPC — запускаемой из командной строки), но если уж есть возможность пользоваться средой программирования — то лучше использовать для контроля за переменными одно из специальных средств IDE: окно Watches (Просмотр) или диалоговое окно Evaluate and Modify (Вычисление и модификация).

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

Элементы выражений отладчика

┌────────────────┬────────────────────────────────────────────────────┐
│Элемент         │Допустимые значения                                 │
│выражения       │                                                    │
├────────────────┼────────────────────────────────────────────────────┤
│                │Все допустимые типы: Boolean, Byte, Char,           │
│Константы       │перечислимый тип, Integer, Longint, Real, Shortint, │
│                │Word и строковый тип.                               │
├────────────────┼────────────────────────────────────────────────────┤
│Переменные      │Все типы, включая типы, определенные пользователем. │
├────────────────┼────────────────────────────────────────────────────┤
│   целочисленный│Любое целочисленное выражение с переменными         │
│тип             │границами диапазона.                                │
├────────────────┼────────────────────────────────────────────────────┤
│   тип с        │Любые выражения с плавающей точкой или целочисленные│
│плавающей точкой│выражения; лишние значащие цифры отбрасываются.     │
├────────────────┼────────────────────────────────────────────────────┤
│                │Любое символьное выражение, включая печатаемые      │
│   символьный   │символы в одинарных кавычках, целочисленные         │
│тип             │выражения, тип которых приведен к типу Char, и      │
│                │контанты ASCII (#xx).                               │
├────────────────┼────────────────────────────────────────────────────┤
│   булевский тип│True, False и все булевские выражения.              │
├────────────────┼────────────────────────────────────────────────────┤
│   перечислимый │Любые совместимые перечислимые константы или        │
│тип             │целочисленные выражения в рамках диапазона, тип     │
│                │которых приведен к совместимому перечислимому типу. │
├────────────────┼────────────────────────────────────────────────────┤
│                │Любые совместимые указатели или выражения с         │
│   указатель    │приведенными к ним типами; функция Ptr с            │
│                │соответствующим параметрами.                        │
├────────────────┼────────────────────────────────────────────────────┤
│                │Любая строковая константа (текст в одинарных        │
│   строковый тип│кавычках); строковые переменные; строковые          │
│                │выражения, состоящие из конкатенированных строковых │
│                │констант и переменных.                              │
├────────────────┼────────────────────────────────────────────────────┤
│                │Любая множественная константа; любое выражение,     │
│   множество    │совместимое с множественным типом, в котором        │
│                │используются операции +, - и *.                     │
├────────────────┼────────────────────────────────────────────────────┤
│Приведение типа │Соблюдаются стандартные правила Паскаля.            │
├────────────────┼────────────────────────────────────────────────────┤
│Операции        │Все операции Borland Pascal.                        │
├────────────────┼────────────────────────────────────────────────────┤
│Встроенные      │Все функции, допустимые в выражениях-константах.    │
│функции         │                                                    │
├────────────────┼────────────────────────────────────────────────────┤
│Массивы         │Массивы Borland Pascal - Mem, MemL, MemW.           │
└────────────────┴────────────────────────────────────────────────────┘

Разберем использование окна Watches

Вначале это окно нужно отобразить на экране. Делается это выбором пункта
меню Debug → Watch. На экране появится пустое окно с соответствующим заголовком.

Теперь запускаем программу в пошаговом режиме (нажатием клавиши F7, или
выбором меню «Run → Trace Into»), в редакторе устанавливаем курсор на
название переменной, за которой будем «следить», и жмем Ctrl+F7 (или меню
«Debug → Add Watch…») и подтверждаем выбор нажатием «Ok»… Всё…
Переменная добавлена в окно Watches, и можно наблюдать за ее значением на Watch каждом шаге выполнения программы…

Примечание: Если выбрать переменную для просмотра без предварительного
отображения пустого окна Watches на экране, ничего страшного не произойдет: IDE автоматически откроет окно Watches самостоятельно.

Например, после выполнения выделенной строки

i := 15;

значение переменной i будет уже равно не 0, а 15…

В окне Watches могут отображаться любые типы констант/переменных, объявленных в программе. Например, если описан массив …

const
  arr: array[1 .. 10] of integer = (
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10
  );

… то можно просмотреть одновременно (!!!) как весь этот массив, так
и его левую и правую части… Для этого достаточно ввести во втором и Просмотр третьем случае не только название массива, но и стартовый элемент, и массива (через запятую) число повторений.

Кроме массивов и переменных встроенных типов возможно просматривать Просмотр также и записи (либо в простом формате — только имя переменной, либо в записи специальном — с добавлением спецификатора R.

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

┌──────┬─────────────┬────────────────────────────────────────────────────────┐
│      │Тип, на      │                                                        │
│Символ│который он   │Функция                                                 │
│      │влияет       │                                                        │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│$, H  │целочисленные│Шестнадцатиричный. Выводит целочисленные значения с     │
│или X │типы         │префиксом $, включая те, которые содержатся в структуре │
│      │             │данных.                                                 │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│      │Char,        │Символьный. Выводит специальные символы для кодов ASCII │
│C     │строковые    │0..31. По умолчанию такие символы выводятся в виде      │
│      │типы         │значений #xx.                                           │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│      │целочисленные│Десятичный. Выводят целочисленные значения в десятичном │
│D     │типы         │виде (включая те, которые содержатся в структурах       │
│      │             │данных).                                                │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│Fn    │с плавающей  │С плавающей точкой. Выводит n значащих цифр, где n лежит│
│      │точкой       │в диапазоне 2..18 (по умолчанию - 11).                  │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│      │             │Дамп памяти. Выводит n байт памяти, начиная с адреса,   │
│nM    │все          │указываемого выражением. Если n не задано, то по        │
│      │             │умолчанию оно равно значению размера в байтах типа      │
│      │             │переменной.                                             │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│P     │указатели    │Указатель. Выводит указатели в формате сегм:смещ (а не  │
│      │             │Ptr(сегм:смещ), как это делается по умолчанию.          │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│R     │записи,      │Запись. Выводит имена полей, например, (X:1;Y:10; Z:5)  │
│      │объекты      │вместо (1, 10,5).                                       │
├──────┼─────────────┼────────────────────────────────────────────────────────┤
│      │             │Строки. Выводит символы ASCII 0..31 в виде #xx.         │
│S     │Char, строки │Использует только для модификации дампов памяти (см.    │
│      │             │выше nM).                                               │
└──────┴─────────────┴────────────────────────────────────────────────────────┘

Окно Evaluate and Modify

Но кроме простого просмотра значений той или иной переменной или выражения,
существует средство, позволяющее вам в любой момент вычислять выражения и
изменять на этапе выполнения значения переменных. Этим средством и является
диалог Evaluate and Modify (Вычисление и модификация).

Вычисление выражений

Чтобы вычислить выражение, выбираем команду Debug → Evaluate/Modify или нажимаем клавиши Ctrl+F4. Отладчик выводит диалоговое окно Evaluate and Modify (Вычисление и модификация). Здесь (в поле ввода Expression) можно занести любое допустимое выражение , или выбрать его из списка ранее вычисленных при помощи этого же диалога выражений и отредактировать.

После нажатия на Enter или щелчка мышью на кнопке Evaluate (Вычислить), текущее значение выражения будет показано в поле Result (Результат).

Примечание: если в поле Expression введено выражение, которое не может быть вычислено интегрированной средой, то в поле Result появится вот такая надпись: «Cannot evaluate this expression».

Модификация переменных

Кроме этого, во время отладки с помощью диалогового окна Evaluate and Modify существует возможность поменять значение переменной на любое другое, чтобы проверить работу программы с другим, вновь присвоенным значением переменной. Для этого нужно установить курсор на имени переменной, и выбрать в меню Debug → Evaluate/Modify… (или просто нажать Ctrl+F4)…

В появившемся окне в поле Expression (Выражение) достаточно ввести имя переменной (или ничего не делать, если имя уже введено), и нажать кнопку Evaluate… Текущее значение выбранной переменной будет отображено в поле Result. Если оно же отображается и в поле New Value, это значит, что у Вас есть возможность прямо сейчас поменять это значение на любое другое (разумеется, совместимое по присваиванию с типом выбранной переменной; присваивать строке целому числу Вам никто не позволит, также, как и, например, записать в целочисленную переменную значение 3.14159), и применить новое значение переменной, не перезапуская программу…

Например, допустим, что программа имеет вид:

var
  i: integer;
begin
  for i := 1 to 20 do
    writeln(i);
  readln;    
end.

, и Вам захотелось попасть в точку, где распечатывается значение i = 20 (желание далеко не самое сумасшедшее, представьте, например, что вместо простого распечатывания значения i там будет вызов какой-нибудь функции, которую надо прогнать пошагово при определенном значении i, да еще и функция может быть длинной и долго выполняться), но не очень хочется нажимать F7 почти 20 раз и приходить в нужную точку «естественным путем». Что делаем? А вот что:

Добавляем значение i в окно Watches, начинаем выполнять программу пошагово (F7)… Я остановился, когда значение i было равно трем, хотя это же самое можно было сделать и сразу после входа в цикл, то есть как только i стало равно единице.

Теперь ставим курсор под название переменной i и жмем Ctrl+F4 для вызова нужного нам окна… Состояние экрана, которое должно получиться, видно на скриншоте…

Переходим в поле New Value (как я говорил, если в нем записано текущее значение переменной, то нам будет позволено его сменить), печатаем в нем значение 20, и жмем на «Modify»…

Как видим, значение i в Watches тоже поменялось на 20, теперь спокойно закрываем окно «Evaluate and Modify» (кнопкой Cancel), и продожлжаем выполнять программу пошагово…

Таким образом, мы пропустили все НЕинтересующие нас в данном случае шаги,
выполнение которых могло занять значительное время…

Окно Call Stack — что это такое?

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

Да и не нужно этого держать в голове. Для этого существует такое средство, как «Call Stack» (вызывается из меню Debug → Call Stack или просто Ctrl+F3). Например, пусть наша программа имеет вид:

function fact(n: longint): longint;
begin
  if n = 0 then fact := 1
  else fact := n * fact(n - 1);
end;
 
function b(n: longint): integer;
begin
  b := 2 * fact(n);
end;
 
begin
  writeln( b(10) );
end.

Если начать выполнять ее пошагово, очень скоро можно запутаться в том, что именно сейчас выполняется (факториал какого числа вычисляется в данный момент, к примеру), и что еще осталось НЕзавершенным. А если программа будет в 10 раз длиннее, и будет содержать не 2, а 10 процедур/функций? В таком случае достаточно вызвать окно Call Stack (способ вызова — выше), и посмотреть, что именно в данный момент выполняется (то есть находится на першине стека вызовов), и что еще выполняться будет (находится ниже в списке), вплоть до Program, обозначающего, самый нижний уровень — основную программу…

Вот, например, в данном случае: выполняется функция вычисление факториала 8, которая вызвана из нижестоящей в списке функции вычисления факториала 9, которая в свою очередь… Ну, дальше все понятно… При продолжении пошагового выполнения этой программы в окно Call Stack будут добавляться новые и новые вызовы Fact (7), Fact(6), … до Fact(0); потом рекурсия начнет раскручиваться обратно…

Кстати, Call Stack — незаменимый помощник именно при работе с рекурсивными подпрограммами, поскольку дает возможность контролировать последовательность вызовов рекурсивной функции, и на ранней стадии определить, например, бесконечную рекурсию…
Например, здесь — совершенно очевидно, что рекурсивная функция оформлена неверно (отсутствует ветка Else), сразу после того, как в окне Call Stack появились вызовы f (-1) и f(-2)…

Еще одно полезное применение окна Call Stack — если вы случайно начали трассировку кода, который хотели бы выполнить за один шаг. В стеке вызовов вы можете найти тот вызов, который начали трассировать по ошибке, затем выбрать команду Run to Cursor, чтобы выполнить за один шаг остальную часть вызова.

Что такое точки останова программы?

Кроме всех вышеперечисленных возможностей, значительно облегчающих жизнь программисту, в IDE Паскаля встроено еще одно средство, очень мощное и эффективное (при правильном использовании)… Это — работа с точками останова программы (BreakPoints).

Точка останова — это обозначенная в коде программы позиция, в которой вы хотите прекратить выполнение программы и вернуть выполнение отладчику. В этом смысле точка останова работает аналогично команде GoTo Cursor, при которой программа выполняется обычным путем до достижения определенной точки. Основное различие состоит в том, что вы можете задать несколько точек останова и точки останова, которые будут срабатывать не при каждом их достижении.

Допустим, есть следующая программа:

const
  parameter = 10;
 
function f(x: integer): integer;
begin
  f := 10 * parameter - sqr(x);
end;
 
var
  i, j: integer;
  arr: array[1 .. 20] of real;
begin
  for i := 1 to 20 do begin
    j := f(i);
    arr[i] := (15 * j / parameter) + i / j - 8;
  end;
  { ... }
end.

(не обольщайтесь, программа может быть не в 17, а в 1700 строк длиной, и функция f может быть гораздо более сложной, так же как и способ ее вызова)…

Естественно, запустив эту программу, получаем:

Runtime error 200 at 0006:0004.

, из чего заключаем, что где-то в программе происходит деление на 0. Ну, где
оно происходит, понятно. А вот на какой итерации? Чему равно i, при котором
происходит эта ошибка? Можно, конечно, воспользоваться старым и проверенным
способом, и сделать так:

const
  parameter = 10;
 
function f(x: integer): integer;
begin
  f := 10 * parameter - sqr(x);
end;
 
var
  i, j: integer;
  arr: array[1 .. 20] of real;
begin
  for i := 1 to 20 do begin
    j := f(i);
    writeln('j = ', j);
    arr[i] := (15 * j / parameter) + i / j - 8;
  end;
  { ... }
end.

, после чего нам будут распечатаны все значения j, для которых программа отработала нормально, и еще одно, при котором как раз и произошло «Деление на Ноль». Но для этого нужно вносить изменения в программу. А можно обойтись без её изменений… Используя точку останова…

Для этого проделаем следующее… Во-первых, добавим переменную i в список Watches, так как нам нужно найти именно «при каком i программа вылетает».

Далее — установим курсор на той строке программы, где происходит деление, и выберем в меню пункт «Debug → Add Breakpoint…» Экран примет вид, показанный на снимке справа.

Примечание: строка, на которую устанавливается BreakPoint, должна содержать выполняемый код и не может быть комментарием, описанием или пустой строкой…

В поле Condition внесем условие, при котором следует остановить программу (условие вводится так же как и при использовании условных операторов в программе, только Условный If здесь присутствовать не должно), и подтверждаем установку BreakPoint-а нажатием кнопки «Ok»:

Строка, в которой установлен хотя бы один BreakPoint (а устанавливать можно несколько точек останова для программы, причем даже на одной строке, но с разными условиями, может быть установлено более одного BreakPoint-а) меняет цвет на красный…

Если теперь запустить программу (обычным способом — через Ctrl+F9, или пошагово, не имеет значения), то как только значение j в Условный выделенной строке станет равным 0, прогон программы будет приостановлен с выдачей вот такого сообщения:

Как видим (в окне Watches), происходит это при i = 10… Что и требовалось
определить…

Чтобы просмотреть, какие BreakPoint-ы были установлены в программе, достаточно зайти в меню «Debug → BreakPoints», и будет выведен список всех точек останова для данной программы:

Нажатием на «Clear All» можно удалить все точки останова сразу, «Delete» удалит только подсвеченный BreakPoint, а «Edit»-ом можно отредактировать текущий (подсвеченный) BreakPoint — подкорректировать условие, поменять номер строки, в которой должна производиться проверка, изменить счетчик числа проходов (задание для точки останова счетчика проходов сообщает отладчику, что останавливать программу нужно не при каждом достижении точки останова, а только на n-ый раз. То есть, если счетчик проходов равен 3, то отладчик останавливает программу только при третьем достижении данной точки останова) и т.д.

Поиск нужного места

IDE предусматривает два способа поиска в программе заданного места. Простейший способ предоставляет команда Find Procedure (Поиск процедуры) из меню Search. Эта команда запрашивает у Вас имя процедуры или функции, затем находит соответствующую строку в файле, где определяется эта подпрограмма. Этот подход полезно использовать при редактировании, но его можно комбинировать с возможностью выполнения программы до определенной точки, чтобы пройти программу до той части кода, которую вы хотите отладить.

Повторное выполнение (сброс программы)

В ходе сеанса отладки иногда желательно начать все сначала. Выберите команду Run → Reset Program или нажмите клавиши Ctrl+F2. Это приведет к полному сбросу, так что выполнение по шагам, или трассировка начнется в начале основной программы.

Отслеживание вывода программы

При выполнении программы по шагам часто полезно просмотреть вывод программы, называемый экраном пользователя. IDE предоставляет несколько способов просмотра экрана пользователя.

Переключение экранов

В любой момент сеанса отладки вы можете выполнять переключение экрана IDE и экрана пользователя. Чтобы вывести экран пользователя, нажмите клавиши Alt+F5. Чтобы вернуться в IDE, нажмите любую клавишу или щелкните «мышью».

Окно Output

IDE для DOS предусматривает для экрана пользователя окно, которое называется окном вывода. Выбрав команду меню Debug → Output, вы можете открыть (вывести на передний план) активное окно, содержащее вывод программы. Настроить размер этого окна можно аналогично окну редактирования.

2.16.1. Отладка в жизни программиста

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

Для начала мы попытаемся сформулировать ряд базовых принципов, связанных с отладкой, и сделаем это в такой форме, что они, возможно, покажутся вам шуткой; вы вскоре сами убедитесь, что в этой шутке доля шутки совсем незначительна, а всё остальное — самая настоящая лютая правда. Итак:

• ошибка всегда есть;

• ошибка всегда не там;

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

• если вы считаете, что программа должна работать, то самое время вспомнить, что “должен” — это когда взял взаймы и не отдал;

• если отладка — это процесс исправления ошибок, то написание программы — это процесс их внесения;

• сразу после обнаружения ошибки дело всегда выглядит безнадёжным;

• найденная ошибка всегда кажется глупой;

• чем безнадёжнее всё выглядело, тем глупее кажется найденная ошибка;

• компьютер делает не то, чего вы хотите, а то, о чём вы попросили;

• корректная программа работает правильно в любых условиях, некорректная — тоже иногда работает;

• и лучше бы она не работала;

• если программа работает, то это ещё ничего не значит;

• если программа “свалилась”, надо радоваться: ошибка себя проявила, значит, её теперь можно найти;

• чем громче грохот и ярче спецэффекты при “падении” программы, тем лучше — заметную ошибку искать гораздо проще;

• если ошибка в программе точно есть, а программа всё-таки работает, вам не повезло — это самый противный случай;

• ни компилятор, ни библиотека, ни операционная система ни в чём не виноваты;

• никто не хочет вашей смерти, но если что — никто не расстроится;

• на самом деле всё совсем не так плохо — всё гораздо хуже;

• первая написанная строчка текста будущей программы делает этап отладки неизбежным;

• если вы не готовы к отладке — не начинайте программировать;

• компьютер не взорвётся; но большего вам никто не обещал.

В компьютерных классах часто (особенно на контрольных работах и зачётах) можно наблюдать студентов, которые, написав некий текст на языке программирования, добившись с горем пополам успешной компиляции и убедившись, что полученный результат никак не отвечает поставленной задаче, на этом какую-либо конструктивную деятельность прекращают, переключаясь, например, на другую задачу — как правило, с аналогичным результатом на выходе. Столь странный выбор стратегии они обычно объясняют сакраментальной фразой “ну, я её написал, а она не работает”, причём произносится с интонацией, подразумевающей, что во всём виновата сама программа, а ещё преподаватель, компьютер, погода в Африке, посол Аргентины в Швеции или буфетчица из студенческой столовой, но уж точно не говорящий — ведь он же написал программу.

В такой ситуации следует сразу же вспомнить один простой принцип: компьютер делает ровно то, что написано в программе. Этот факт кажется банальным, но из него немедленно следует второй, а именно: если программа работает неправильно, то она неправильно написана. С учётом этого утверждение “я написал программу” требует уточнения: правильнее будет сказать “я написал неправильную программу”.

Ясно, что написание неправильной программы, пусть даже успешно проходящей компиляцию, уж точно не является сколько-нибудь достойным внимания делом; в конце концов, простейший текст на Паскале, успешно проходящий компиляцию, состоит всего из двух слов и одной точки: “begin end.” Конечно, эта программа не решает поставленную задачу — но ведь и та, которую “написали, а она не работает”, тоже ничего не решает, и чем же она в таком случае лучше?

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

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

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

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

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

Избежать отладки невозможно, но соблюдение некоторых достаточно простых правил может её изрядно облегчить. Итак, самое главное: старайтесь проверять работу отдельных частей программы по мере их написания. Здесь на вас работают сразу два закона: во- первых, только что написанный код отлаживать гораздо проще, чем тот, который вы уже успели подзабыть; во-вторых, с ростом объёма текста, который нужно отлаживать, сложность отладки растёт нелинейно. Кстати, из этого правила вытекает довольно очевидное следствие: старайтесь разбивать программу на подпрограммы так, чтобы они как можно меньше зависели друг от друга; помимо других выгод, этот подход позволит упростить раздельное тестирование частей вашей программы. Можно предложить ещё более общий принцип: когда вы пишете код, думайте о том, как вы будете его отлаживать. Отладка не прощает безалаберности, проявленной на стадии кодирования; даже такое “безобидное” нарушение стиля оформления, как короткое тело оператора ветвления или цикла, оставленное на одной строчке с заголовком оператора, может вам стоить изрядного количества впустую испорченных нервов.

Второе правило мы уже видели в начале параграфа в виде простой и ёмкой фразы: ошибка всегда не там. Если у вас возникла “интуитивная уверенность”, что к тому эффекту, который вы наблюдаете, может привести, конечно же, только ошибка вот в этой процедуре, вот в этом цикле, вот в этом фрагменте — не верьте своей интуиции. В целом интуиция — прекрасная штука, но во время отладки программ она не работает. Объясняется это очень просто: если бы ваша интуиция чего-то стоила против данной конкретной ошибки, то вы бы эту ошибку не допустили. Итак, прежде чем пытаться исправить тот или иной фрагмент, вам необходимо объективно (а не “интуитивно”) убедиться в том, что ошибка находится именно здесь. Помните: в таком месте программы, где вы знаете, что можно ошибиться, вы скорее всего не ошибётесь; напротив, самые заковыристые ошибки оказываются как раз там, где вы никак не могли их ожидать; между прочим, именно поэтому они там и оказываются.

К объективным методам локализации ошибок относятся отладочная печать и пошаговое выполнение под управлением программы-отладчика; если вы надеетесь без них обойтись, лучше вообще не начинайте писать программы; и здесь мы подходим к третьему правилу: метод пристального взгляда в ходе отладки практически не работает. Сколько бы вы ни пялились в свой текст, результат будет выражаться фразой “вроде всё правильно, почему же она не работает?!” Опять же, причина здесь достаточно очевидна: если бы вы могли увидеть собственную ошибку, вы бы не ошиблись. Можно назвать ещё два соображения в пользу неэффективности “пристального взгляда”: наиболее внимательно вы будете просматривать те фрагменты своего кода, где ожидаете обнаружить ошибку, а она, как мы уже знаем, наверняка не там; плюс к тому здесь включается такое хорошо известное явление, как “замыленность взгляда” — даже глядя прямо на ту строчку программы, в которой допущена ошибка, вы вряд ли ошибку заметите. Причину этого эффекта тоже несложно понять: вы сами только что написали этот фрагмент кода, задействовав некие соображения, которые кажутся вам правильными, и, как следствие, сам фрагмент кода продолжает вам казаться правильным, даже если на самом деле содержит ошибку. Итак, не тяните резину и не тратьте драгоценное время на “внимательное изучение” собственного кода: отлаживать программу всё равно придётся.

Отметим здесь ещё один момент: переписывание программы заново — в целом дело хорошее, но избежать отладки это вам не поможет; скорее всего, вы просто снова наделаете ошибок в тех же местах. Что касается переписывания заново отдельных фрагментов программы, то с этим всё ещё хуже: ошибка наверняка окажется не в том фрагменте, который вы решите переписать.

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

Ещё один момент, который стоит учитывать: если вы сами не можете найти ошибку в своей программе, то никто другой её тем более не найдёт. Студенты часто задают один и тот же вопрос: “а почему моя программа не работает?” Ваш покорный слуга, слыша этот вопрос, обычно, в свою очередь, спрашивает, за кого его изволят держать: за экстрасенса, за телепата или за ясновидящего. Разобраться в вашей программе стороннему человеку в большинстве случаев сложнее, чем написать аналогичную программу с нуля. Кроме того, это же ваша программа; сами наворотили, сами разбирайтесь. Интересно, что в подавляющем большинстве случаев студент, задающий такой вопрос, даже не пытался ничего сделать для отладки своей программы.

Закончить этот параграф мы попробуем в позитивном ключе. Отладка — дело неизбежное и очень тяжёлое, но, как это часто бывает, процесс отладки оказывается занятием весьма увлекательным, даже азартным. Некоторые программисты заявляют, что программа-отладчик — это их любимая компьютерная игра, поскольку никакая стратегия, никакой пасьянс, никакие аркады не дают такого разнообразия головоломок и пищи для мозгов, никакие леталки и стрелялки не приводят к выделению такого количества адреналина, как процесс отладки, и никакие успешные прохождения квестов не приносят такого удовлетворения, как успешно найденная и изничтоженная ошибка в программе. Как несложно догадаться, вопрос тут исключительно в вашем личном отношении к происходящему: постарайтесь воспринимать это как игру с ошибкой в “кто кого”, и вы увидите, что даже этот аспект программирования способен доставлять удовольствие.

2.16.2. Тесты

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

Начинающие, как правило, “тестируют” свои программы очень просто: запускают, набирают какие-то входные данные и смотрят, что получится. Такой подход на самом деле никуда не годится, но это, увы, становится понятно не сразу и не всем; автору приходилось встречать профессиональные команды программистов, в которых даже есть специально нанятые тестировщики, и они с утра до вечера делают именно это: гоняют тестируемую программу и так и этак, вколачивая разнообразные данные в те или иные формы ввода, нажимая на кнопочки и совершая другие телодвижения в надежде рано или поздно наткнуться на какую-нибудь несообразность. Когда программисты вносят в программу изменения, работа таких “тестировщиков” начинается с самого начала, ведь, как известно, при любых изменениях сломаться может что угодно.

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

Чтобы понять, в чём такой студент неправ и как действовать правильно, вспомним, что поток стандартного ввода не обязательно связан с клавиатурой; при запуске программы мы можем сами решить, откуда она будет читать информацию. Мы уже использовали это, причём речь шла о тестировании очень простых программ; даже для программы, которой на вход требуется подать всего одно целое число, мы предпочли не вводить это число каждый раз, а воспользовались командой echo. Конечно, число всё-таки приходится набирать, когда мы формируем команду, но сама команда остаётся в истории, которую для нас запоминает командный интерпретатор, так что второй раз нам то же число набирать не нужно: вместо этого мы воспользуемся “стрелкой вверх” или поиском через Ctrl-R (см. § 1.4.6), чтобы повторить команду, которую уже вводили.

Конечно, использовать возможности командного интерпретатора для хранения и повторного прогона тестовых примеров можно разве что в самых простых случаях; если подходить к делу правильно, то для проверки работы программы следует создать набор тестов, представленный в каком-то объективном виде — как правило, в виде файла или нескольких файлов.

Под тестом понимается, и это очень важно, вся информация, которая нужна, чтобы запустить программу или какую-то её часть, подать на вход такие данные, которые проявляют тот или иной аспект её функционирования, проверить результат и выдать вердикт о том, правильно всё отработало или нет. Тест может состоять из одних только данных — например, в одном файле мы можем сформировать данные, которые программе следует подать на вход, в другом файле — то, что мы ожидаем получить на выходе. Более сложный тест может включать в себя специальный тестовый программный код — именно так приходится действовать при тестировании отдельных частей программы, например, отдельных её подпрограмм. Наконец, сложные тесты оформляют в виде целых программ — таких, которые сами запускают тестируемую программу, подают ей на вход те или иные данные и проверяют результаты.

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

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

В большинстве случаев начинающие на этом успокаиваются, решив, что программа “правильная”, но задача сокращения дроби не столь проста, как кажется на первый взгляд. Если программу написать “в лоб”, она, скорее всего, не будет работать для отрицательных чисел. Об этом нашему начинающему может сказать его более опытный товарищ или, если дело происходит на занятиях в классе — преподаватель; попробовав запустить свою программу и подать ей на вход что-нибудь “с минусом”, её автор может убедиться, что старшие товарищи правы и программа, к примеру, “зациклилась” (именно это произойдёт с простейшей реализацией алгоритма Евклида, которая не учитывает особенностей работы операции mod для отрицательных операндов). Конечно, исправить программу особых проблем не составляет, важнее другое: любые исправления могут “сломать” то, что до этого работало, так что новую версию программы придётся тестировать с самого начала, то есть тестовые запуски, которые уже были проделаны, придётся повторить, каждый раз вводя числа с клавиатуры.

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

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

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

Осталось придумать какой-нибудь механизм, который, имея набор тестов в таком виде, сам, без нашего участия запустит тестируемую программу нужное число раз, подаст ей на вход тестовые данные и проверит правильность результатов. В нашей ситуации самый простой способ добиться этого — написать скрипт на языке командного интерпретатора; если вы не помните, как это делается, перечитайте § 1.4.13.

Чтобы понять, как наш скрипт будет выглядеть, представим себе, что четыре числа, составляющих тест, располагаются в переменных $а, $b, $с и $d. “Прогнать” тест можно командой “echo $а $b │ ,/frcancel”; но нам нужно не просто запустить программу, а сравнить результат с ожидаемым, для чего результат нужно тоже поместить в переменную. Для этого можно воспользоваться присваиванием и “обратными апострофами”, которые, как мы помним, подставляют вместо себя результат выполнения команды:

Результат, попавший в переменную $res, можно сравнить с ожидаемым, и если обнаружено несовпадение, сообщить об этом пользователю:

Последовательно “загнать” в переменные $а, $b, $с и $d числа из тестов нам поможет встроенная в интерпретатор команда read; в качестве параметров эта команда принимает имена переменных (без знака “$”), читает из своего потока ввода строку, разбивает её на слова и “раскладывает” эти слова по заданным переменным, причём если слов оказалось больше, то в последнюю переменную попадёт весь остаток строки, состоящий из всех “лишних” слов. Команда read обладает полезным свойством: если очередную строку прочитать удалось, она завершается успешно, а если поток кончился — неуспешно. Это позволяет с её помощью организовать цикл while примерно так:

В теле такого цикла переменные $а, $b, $с и $d последовательно принимают своими значениями первое, второе, третье и четвёртое слово из очередной строки. Отметим, что каждый наш тест как раз представляет собой строку из четырёх слов (в роли слов выступают числа, но они ведь тоже состоят из символов; в командно-скриптовых языках нет ничего, кроме строк). В теле цикла мы поместим приведённый выше if, прогоняющий отдельный тест, и останется только придумать, как подать получившейся конструкции на стандартный ввод последовательность наших тестов. Для этого можно воспользоваться перенаправлением вида “документ здесь”, которое делается с помощью знака “<<”. После этого знака ставится некоторое слово (“стоп-слово”), а затем пишется текст, который следует подать на вход команде, и завершается этот текст строкой, состоящей целиком из стоп-слова.

Всё вместе будет выглядеть примерно так:

Несмотря на свою примитивность, это уже самый настоящий полноценный комплект тестов с возможностью автоматического прогона. Как можно заметить, добавление нового теста сводится к вписыванию ещё одной строчки перед END, но это не главное; важнее то, что прогон всех тестов не требует от нас никаких усилий, мы просто запускаем скрипт и смотрим, выдаст ли он что-нибудь. Если он ничего не выдал — прогон прошёл успешно. Общее правило, которому мы фактически уже последовали, звучит так: тест может быть трудно написать, но должно быть легко прогнать.

Дело тут вот в чём. Тесты нужны не только для того, чтобы попытаться выявить ошибки сразу после написания программы, но и для того, чтобы после каждого исправления можно было до какой-то разумной степени уверить себя, что мы, внося изменения, ничего не сломали. Поэтому отладку никогда не следует считать оконченной, а тесты ни в коем случае не надо выбрасывать (например, стирать) — они ещё не раз пригодятся; и, конечно же, необходимо рассчитывать на то, что после любых мало-мальски заметных изменений в программе нам нужно будет подвергнуть её проверке на всех имеющихся у нас тестах, а делать это вручную, понятное дело, несколько накладно.

Если очередной тест выявил ошибку в программе, не торопитесь бросаться что-то исправлять. Для начала стоит подумать, нельзя ли упростить тест, на котором проявилась ошибка, то есть нельзя ли написать тест, проявляющий ту же ошибку, но при этом более простой. Конечно, это не значит, что более сложный тест при этом нужно выбросить. Тесты вообще не надо выбрасывать. Но чем тест проще, тем меньше факторов, которые могут повлиять на работу программы, и тем легче будет найти ошибку. Последовательно упрощая один тест, вы можете создать целое семейство тестов, причём, возможно, самые простые из них уже не будут проявлять ошибку. Это не повод останавливаться: попробуйте взять самый простой из тестов, который всё ещё “ошибается”, и упростить его в каком-нибудь другом направлении. В любом случае все созданные тесты, вне зависимости от того, проявляют ли они прямо сейчас какую-то ошибку или нет, ценны для дальнейшей отладки: одни могут указать путь поиска ошибки, другие — показать, где ошибку искать точно не надо.

Существует особый подход к написанию программ, который называется test first — на русский это можно приблизительно перевести как “тест сначала”. При этом подходе сначала пишут тесты, запускают их, убеждаются, что они не работают, а затем пишут текст программы так, чтобы заставить тесты заработать. Если программисту начинает казаться, что программа всё равно написана не так, как должна быть, ему нужно сначала написать новый тест, который, не сработав, тем самым даст некое объективное подтверждение “неправильности” программы, к лишь затем изменить программу так, чтобы проходил к новый тест, к все старые. Написание программного текста, предназначенного для чего-то иного, кроме удовлетворения имеющихся тестов, полностью исключается.

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

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

2.16.3. Отладочная печать

Когда из тестов выжато всё что только можно, фантазия на тему “что бы ещё проверить” окончательно иссякла, а программа продолжает работать неправильно, наступает момент, когда необходимо понять, почему тесты дают столь неожиданные результаты; иначе говоря, нужно выяснить, что в действительности происходит в программе.

Пожалуй, самый “дешёвый и сердитый” способ для этого — вставить в программу дополнительные операторы, которые будут что-то печатать. Информация, которую такие операторы печатают, не имеет отношения к решаемой задаче, она нужна только в процессе отладки; собственно говоря, всё это так и называется — отладочная печать. Чаще всего отладочная печать позволяет выяснить ответы на два вопроса: “доходит ли программа до этого места” и “как изменяется (какое значение получает) эта переменная”.

Первое, что нужно запомнить относительно отладочной печати: отладочные сообщения должны быть легко узнаваемы и не должны сливаться с остальной информацией, которую выдаёт ваша программа. Можно начать каждое отладочное сообщение, например, с пяти звёздочек, или со слова “DEBUG” (обязательно заглавными буквами, если только ваша программа штатно не выдаёт сообщений заглавными — в таком случае маркер отладочной печати стоит набрать, напротив, строчными), или с лаконичного “XXX”; главное — чтобы отладочную печать было хорошо видно. Второе простое правило для отладочной печати — не забывайте про переводы строк; для Паскаля это означает, что нужно применять writeln. Дело тут в так называемой буферизации вывода; сообщение, которое не закончилось переводом строки, вы можете увидеть не сразу, а если программа завершится аварийно — то и вообще не увидеть, что совершенно не годится для отладочной печати.

Если говорить точнее, операции вывода помещают информацию в буфер, из которого она отдаётся операционной системе для выдачи в поток в определённых случаях: при заполнении буфера, при завершении программы, при вызове процедуры, принудительно очищающей буфер (для Free Pascal такая процедура называется flush; в частности, flush(output) принудительно вытесняет буфер стандартного потока вывода). Кроме того, при выводе на терминал (в отличие от вывода в файл) вытеснение производится также при выдаче перевода строки к при затребовании программой операции ввода — на случай, если перед этим было выдано приглашение к вводу.

Ещё один момент, связанный с отладочной печатью, довольно очевиден, но некоторым ученикам это почему-то приходится повторять по несколько раз: для операторов, связанных с отладочной печатью, структурные отступы никто не отменял. Даже если вы намерены через пять минут вычистить из текста программы вставляемые операторы, это не повод превращать текст программы в нелепые каракули, пусть даже всего лишь на пять минут.

Впрочем, не торопитесь убирать из текста отладочную печать. Как показывает практика и гласит вселенский закон подлости, как только из программы будет убран последний оператор отладочной печати, в ней тут же обнаружится очередная ошибка, для отлова которой большую часть только что убранных операторов придётся вставить обратно. Будет лучше взять отладочные операторы в фигурные скобки, превратив их в комментарии (но не нарушая при этом структурных отступов!) Однако даже вставка и удаление знаков комментария может оказаться неоправданно трудоёмким делом. Правильнее будет воспользоваться директивами условной компиляции, которые пришли в Паскаль из языка Си и на первый взгляд выглядят довольно странно. Для условной компиляции используются “символы”, которые нужно “определять”; ни для чего другого они не годятся, в отличие от Си, где основная роль аналогичных “символов” совершенно иная. Так или иначе, придумайте себе какой-то идентификатор, который вы будете использовать в качестве “символа” для включения и отключения отладочной печати и больше ни для чего; можно порекомендовать на эту роль слово “DEBUG”. Поместите в начале программы директиву “{$DEFINE DEBUG}”, которая “определит” этот символ. Теперь каждый фрагмент программы, предназначенный для отладочной печати, поместите между директивами условной компиляции, примерно так:

Пока в начале программы есть директива, определяющая символ DEBUG, такой оператор writeln будет учитываться компилятором, как обычно, но если убрать директиву DEFINE, “символ” DEBUG станет неопределён, так что всё, что заключено между {$IFDEF DEBUG} и {$ENDIF}, компилятор просто проигнорирует. Заметим, директиву DEFINE даже не обязательно убирать полностью, достаточно убрать из неё символ “$”, и она превратится в обычный комментарий, а вся отладочная печать отключится; если отладочная печать потребуется снова, достаточно будет вставить символ на место. Но можно сделать ещё лучше: директиву DEFINE в программу вообще не вставлять, а символ при необходимости определять из командной строки компилятора. Для этого достаточно добавить в командной строке флажок “-dDEBUG”, примерно так:

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

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

2.16.4. Отладчик gdb

Отладочная печать — средство, бесспорно, мощное, но в ряде случаев мы можем разобраться в происходящем гораздо быстрее, если нам позволят выполнить нашу программу по шагам с просмотром текущих значений переменных. Для этого используется специальная программа, которая называется отладчиком; в современных версиях ОС Unix, в том числе Linux, наиболее популярен отладчик gdb49, его мы сейчас и попробуем задействовать.

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

Отладочная информация занимает сравнительно много места в исполняемом файле, никак не отражаясь на исполнении программы — она нужна только при использовании отладчика. Поэтому компилятор не снабжает исполняемый файл отладочной информацией, если его об этом не попросить, указав в командной строке ключ -g:

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

Отладчик gdb представляет собой программу, имеющую свой собственный встроенный интерпретатор командной строки; все действия с нашей программой мы выполняем, давая отладчику команды. Отладчик умеет работать в разных режимах — в частности, его можно подключить к уже запущенной программе (процессу), а также с его помощью можно разобраться, в каком месте программы и по каким причинам произошло аварийное завершение50, но нам пока будет достаточно разобраться только с одним, наиболее популярным режимом, при котором отладчик сам запускает нашу программу и контролирует ход её выполнения, повинуясь нашим командам. Командная строка, встроенная в gdb, оснащена функциями редактирования, автодополнения (только дополняются, естественно, не имена файлов, а имена переменных и подпрограмм), хранения истории введённых команд и поиска по ней, так что работать с gdb оказывается довольно удобно — при условии, что мы умеем это делать.

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

Если нужно передать нашей программе те или иные аргументы командной строки, это делается с помощью ключа —args, например:

(в этом примере программа myprog будет запущена с тремя аргументами командной строки — abra, schwabra и kadabra).

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

(gdb)

Начать выполнение программы мы можем командой start, в этом случае отладчик запустит нашу программу, но остановит её на первом же операторе главной части, не позволив ей ничего сделать; дальнейшее выполнение будет происходить под нашим контролем. Можно поступить иначе: дать команду run, тогда программа запустится и будет работать как обычно (то есть так, как она работает без отладчика), и если всё будет в порядке, то программа благополучно завершится, а отладчик так ничего и не сделает; но если выполнение программы прервать нажатием Ctrl-C, то при выполнении под отладчиком программа не будет уничтожена; вместо этого отладчик остановит её и выдаст своё приглашение командной строки, спрашивая нас, что дальше делать. Кроме того, если в ходе выполнения программы под отладчиком произойдёт её аварийное завершение, отладчик покажет нам то место в исходном тексте, где это произошло, и позволит просмотреть текущие значения переменных, что в большинстве случаев позволяет понять, почему произошла авария.

Когда отлаживаемая программа остановлена, мы можем приказать отладчику выполнить в ней один шаг; вопрос в том, что будет считаться “шагом”. Ответов на этот вопрос предусмотрено два. Команда next рассматривает в качестве “шага” одну строку текста исходной программы, причём если в этой строке встречаются вызовы процедур и функций, их выполнение рассматривается как часть “шага”, то есть внутрь вызываемых подпрограмм команда next не заходит. Вторая команда для “одного шага” называется step и отличается тем, что заходит внутрь вызываемых процедур и функций, то есть если в текущей строке присутствовал вызов подпрограммы и мы дали команду step, то после этого текущей станет первая строка текста этой подпрограммы. Команды step и next можно повторять, просто нажимая Enter, что изрядно ускоряет пошаговое выполнение.

Остановив выполнение программы (в том числе после команд step или next), отладчик обычно показывает строку исходного текста, которой соответствует текущая точка выполнения, что в большинстве случаев позволяет сориентироваться и понять, где мы. Если выданной строки недостаточно, можно воспользоваться командой list, которая выдаст на экран окрестности текущей строки — пять строчек перед ней, её саму и пять строчек после. Если и этого не хватает, можно указать команде list номер строки, с которого начать; например, “list 120” выдаст десять строк, начиная со 120-й. При желании можно увидеть следующие десять строк, нажав Enter вместо ввода следующей команды, и так до конца файла.

Если “шагов”, выполняемых программой, оказывается слишком много для пошагового выполнения, мы можем запустить программу на обыкновенное исполнение, в ходе которого она не будет останавливаться после каждого шага; при начальном запуске, как уже было сказано, для этого используется команда run, если же программа была приостановлена, продолжить её выполнение можно командой cont (от слова continue). Обычно перед тем, как воспользоваться одной из этих команд, в программе расставляют так называемые точки останова; дойдя до такой точки, программа остановится, а отладчик выдаст нам приглашение, испрашивая дальнейших указаний. Точки останова устанавливаются с помощью команды break, которой необходим параметр; это может быть либо номер строки исходного текста (а при отладке программы, состоящей из нескольких исходных текстов — имя файла и номер строки, разделённые двоеточием), либо имя подпрограммы (процедуры или функции). В первом случае программа будет остановлена, дойдя до указанной строки (но до того, как эта строка будет выполнена), во втором случае программа остановится, как только будет вызвана указанная подпрограмма.

Отметим, что, поскольку Паскаль не различает в идентификаторах заглавные и строчные буквы, на уровне объектного кода (и в том числе отладочной информации) компилятор приводит все имена к верхнему регистру. Это означает, что при использовании отладчика имена процедур и функций придётся писать заглавными буквами, иначе отладчик нас не поймёт. Формально говоря, то же самое касается и имён переменных, но, например, версии компилятора и отладчика, которые использовал автор этих строк при подготовке книги, прекрасно понимали имена локальных переменных, написанные в любом регистре.

При создании новой точки останова отладчик показывает её номер, которым можно воспользоваться для более гибкой работы с остановками. Например, команда “disable 3” временно выключит точку останова № 3, а команда “enable 3” включит её обратно. Команда “ignore 3 550” укажет отладчику, что точку останова № 3 следует “проследовать без остановки” (проигнорировать) 550 раз, а остановиться лишь после этого — то есть если когда-нибудь до неё дойдёт дело в 551-й раз. Наконец, команда cond (от слова conditional) позволяет задать условие останова в виде логического выражения. Например,

указывает, что останавливаться на точке № 5 следует лишь в том случае, если значение переменной i окажется меньше ста. Команда “info breakpoints” позволяет узнать, какие у вас имеются точки останова, каковы установленные для них условия, счётчики игнорирования и т. п.

Просмотреть значения переменных, когда программа остановлена, можно с помощью команды inspect. При необходимости команда “set var” позволяет изменить значение переменной, хотя это используется сравнительно редко; например, “set var х=50” принудительно занесёт в переменную х значение 50.

В программе, активно использующей подпрограммы, очень полезна может оказаться команда bt (или, если полностью, backtrace). Эта команда показывает, какие подпрограммы были вызваны (но ещё не завершились), с какими параметрами они были вызваны и из каких мест программы. Например, в ходе отладки программы hanoi2 (см. § 2.14.2) команда bt могла бы выдать:

Это означает, что сейчас активна процедура MOVELARGER (в тексте программы она называется MoveLarger), текущая строка — 52-я в файле hanoi2.pas; процедура MoveLarger была вызвана из процедуры SOLVE (Solve), вызов расположен в строке 91. Наконец, Solve вызвана из главной части программы (обозначается словом main; дело тут в том, что gdb ориентирован в основном на язык Си, а в нём вместо главной программы используется функция с именем main), вызов находится в строке 110.

Первое число в каждой строке выдачи команды bt — это номер фрейма. Используя этот номер, мы можем переключаться между контекстами перечисленных подпрограмм; например, чтобы просмотреть значения переменных в точках, где были вызваны нижестоящие подпрограммы. Например, в нашем примере команда “frame 1” позволит нам заглянуть в то место процедуры Solve, где она вызывает MoveLarger. После команды frame можно воспользоваться командами list и inspect, они будут выдавать информацию, относящуюся к текущей позиции выбранного фрейма.

Ещё одна полезная команда — call; она позволяет в любой момент вызвать любую из ваших подпрограмм с заданными параметрами. К сожалению, здесь имеются определённые ограничения; gdb ничего не знает, например, о паскалевских строках, так что, если ваша подпрограмма требует строки в качестве одного из параметров, вы можете вызвать её, указав в качестве параметра какую-нибудь подходящую переменную, но конкретное строковое значение вы задать не можете.

Выход из отладчика производится командой quit, или вы можете устроить ситуацию “конец файла”, нажав Ctrl-D. Кроме того, полезно знать, что в отладчике есть команда help, хотя работать с ней не так просто.

Как было сказано в начале параграфа, gdb может использоваться в разных режимах. Так, если вы уже запустили вашу программу, она ведёт себя неправильно, но вам не хочется повторять действия, которые вызвали такое поведение, либо вы не уверены, что вообще сможете воссоздать имеющуюся ситуацию, можно подключить отладчик к существующему процессу. Для этого нужно, естественно, узнать номер процесса; как это делается, мы рассказывали в § 1.4.7. Далее gdb запускается с двумя параметрами: именем исполняемого файла и номером процесса, например:

Имя исполняемого файла необходимо отладчику, поскольку только из него можно взять отладочную информацию, то есть сведения об именах переменных и номерах строк. После успешного подключения отладчик приостанавливает процесс и ждёт ваших указаний; вы можете с помощью команды bt узнать, где находитесь и как туда попали, воспользоваться командой inspect для просмотра текущих значений переменных, использовать команды break, cont, step, next и т. д. После выхода из отладчика процесс продолжит выполнение, если, конечно, в ходе отладки вы его не убили.

Понравилась статья? Поделить с друзьями:
  • Как проверить ошибку в налогоплательщике
  • Как проверить ошибки в украинском тексте онлайн
  • Как проверить ошибки в тесте в мэш
  • Как проверить ошибки в текстовом документе
  • Как проверить ошибки в тексте эксель