Главная страница
Навигация по странице:

  • Имена переменных, содержащие имена команд

  • Неверное предположение о состоянии программы или данных после вызова

  • Обработка ошибок выполнения процедур

  • Возврат не в ту точку кода

  • Обычно 5 0 6

  • Завершение работы программы

  • 5 0 8

  • Синтаксические ошибки, сообщения о которых отображаются во время выполнения программы

  • Ожидание невозможных условий или комбинаций условий

  • Неверный приоритет пользователя или процесса

  • Неверное начальное значение переменной управления циклом

  • Случайное изменение переменной управления циклом

  • Ошибочный критерий выхода из цикла

  • 5 1 1 Команды, которые должны или не должны выполняться внутри цикла

  • Ошибка вложенности циклов

  • Тестирование-книга. Ю. Н. Артеменко Научный редактор


    Скачать 6.27 Mb.
    НазваниеЮ. Н. Артеменко Научный редактор
    Дата09.10.2019
    Размер6.27 Mb.
    Формат файлаpdf
    Имя файлаТестирование-книга.pdf
    ТипКнига
    #89291
    страница45 из 49
    1   ...   41   42   43   44   45   46   47   48   49
    Реентерабельность
    Реентерабельная программа может параллельно использоваться несколь­
    кими процессами. Реентерабельная подпрограмма может вызывать сама себя или быть вызвана несколькими параллельными процессами одновременно.
    Некоторые языки программирования не поддерживают такой возможнос­
    ти, т.е. повторного входа в процедуры, и при попытке его выполнения

    5 0 4 Часть III: Управление проектами и группами
    программа разрушается. Но даже если язык программирования позволяет процедуре обслуживать несколько процессов, эта возможность сопряжена с целым рядом проблем. В частности, как раздельно хранить данные, пред­
    назначенные для различных процессов, чтобы один процесс не смог раз­
    рушить данные другого?
    Имена переменных, содержащие имена
    команд
    Некоторые языки программирования или их диалекты игнорируют пробелы. В таком языке строка PRINTMYNAME может быть интерпрети­
    рована как PRINT MYNAME. Выполняя эту команду, программа попыта­
    ется распечатать содержимое переменной с именем MYNAME. Если программист на самом деле хотел определить переменную с именем
    PRINTMYNAME, эта попытка приведет к ошибке. Как правило, подобные ошибки выявляют сами программисты, но некоторые из них все же сохра­
    няются в программах.
    Неверное предположение о состоянии
    программы или данных после вызова
    Предположим, что в программе имеется процедура, предназначенная для установки определенного параметра внешнего устройства, например, его скорости передачи информации. Программа вызывает эту процедуру и
    полагает, что она успешно выполнила свою работу. Она немедленно начи­
    нает передачу данных. Однако на этот раз установка скорости не была выполнена. В результате не удается и передача данных, а программа "за­
    висает" в ожидании ответа устройства.
    Другим примером может быть выполнение подпрограммы, масштабиру­
    ющей данные и возвращающей число между 1 и 10. При определенных обстоятельствах эта подпрограмма ведет себя нестандартно, возвращая масштаб в диапазоне от 0 до 10. Поскольку вызывающая подпрограмма не ожидает получить 0, она аварийно завершается при попытке деления на 0.
    Обработка ошибок выполнения процедур
    Предположим, что процедура вычисляет квадратный корень из передан­
    ного ей числа. Если ей передано отрицательное число, она ничего не вы­
    числяет и перед завершением устанавливает флаг ошибки. В данном случае флаг ошибки используется для того, чтобы вызывающая процедура сама могла решить, что ей делать с проблемой. В одном случае может быть выведено сообщение об ошибке, в другом отображена подсказка, а в тре­
    тьем число может быть передано менее скоростной подпрограмме, вычис­
    ляющей квадратные корни из комплексных чисел. Процедуры,
    Приложение: Распространенные программные ошибки 5 0 5
    возвращающие информацию об ошибках в виде флагов, могут вызываться в самых разных ситуациях. В любом случае вызывающая подпрограмма обязательно должна проверить, выполнила ли процедура то, что предпола­
    галось программистом. Однако, если ошибка очень маловероятна, програм­
    мист может забыть о проверке результата. При тестировании, если ошибка все же произойдет, она может показаться невоспроизводимой.
    Возврат не в ту точку кода
    Главным отличием между вызовом подпрограммы и переходом по ко­
    манде GOTO является то, что из подпрограммы управление всегда возвра­
    щается в точку вызова, в то время как после перехода по GOTO возврат вообще не выполняется. Однако иногда управление после вызова подпрог­
    раммы может быть возвращено не в то место программного кода.
    Испорченный стек
    После завершения работы подпрограммы управление передается коман­
    де, непосредственно следующей за командой вызова. Для хранения адре­
    са этой команды используется структура данных, называемая стеком (stack).
    В верхней ячейке стека хранится адрес, помещенный туда последним.
    Именно по нему и возвращается управление после завершения подпрограм­
    мы. Как правило, стек используется не только для хранения адресов воз­
    врата, но и для временного хранения некоторых данных.
    Если подпрограмма помещает в стек некоторые данные и не удаляет их перед своим завершением, в верхней ячейке стека будет вовсе не адрес возврата. Однако компьютер этого не узнает и выполнит передачу управ­
    ления, интерпретировав то, что он найдет в стеке, как адрес. В результате управление будет передано совершенно другому участку памяти. Если там окажутся данные, сбой произойдет немедленно, а если какой-то код, про­
    грамма начнет делать что-то не то и, скорее всего, тоже вскоре аварийно завершит работу.
    Переполнение и выход за нижнюю границу стека
    Стек обычно предназначен для хранения фиксированного количества адресов — например, не более 16, 32 или 128. Предположим, что стек вмещает не более двух адресов. Программа вызывает процедуру 1 и сохра­
    няет в стеке адрес возврата. Затем процедура 1 вызывает процедуру 2 и тоже сохраняет адрес возврата. Когда процедура 2 завершает свою работу, управление возвращается процедуре 1, а по ее завершении — главной про­
    грамме.
    Но что будет, если процедура 2 вызовет процедуру 3? В стеке уже хра­
    нятся два адреса, и адрес возврата из процедуры 3 в него не поместится.
    Такая ситуация называется переполнением стека (stack overflow). Обычно

    5 0 6 Часть III: Управление проектами и группами
    программа или центральный процессор разрешают ее тем, что просто уда­
    ляют из стека самое старое из хранящихся в нем значений и помещают в него новое. После этого из подпрограммы 3 управление передается под­
    программе 2, из подпрограммы 2 подпрограмме 1. А далее... куда переда­
    вать управление после завершения подпрограммы 1 — неизвестно. Такая ситуация называется выходом за нижнюю границу стека (stack underflow).
    ВЫХОД ИЗ
    подпрограммы по
    GOTO вместо RETURN
    Подпрограмма 1 вызывает подпрограмму 2. Последняя, вместо того чтобы нормально завершиться, осуществляет переход в процедуру 1 по команде GOTO. При этом адрес возврата из процедуры 2 остается в сте­
    ке. После завершения процедуры 1 выполняется переход по хранящемуся в стеке адресу — обратно в процедуру 1! Как правило, это не намеренное действие программиста, а ошибка. Чтобы ее избежать, процедура 2 долж­
    на сама удалить из стека свой адрес возврата и только потом осуществить переход в процедуру 1. Такая технология программирования чревата огром­
    ным количеством ошибок (выходами за нижнюю границу стека, возвратом не в ту процедуру, путаницей с возвращаемыми данными и т.п.), поэтому лучше всего ею не пользоваться.
    Прерывания
    Прерыванием называется специальный сигнал, по которому компьютер приостанавливает выполнение текущей программы и передает управление процедуре обработки прерываний. Позднее выполнение программы может быть продолжено. Типичными примерами событий, вызывающих прерыва­
    ния, являются события ввода/вывода, включая сигналы, поступающие от системного таймера.
    Неверная таблица прерываний
    Получив сигнал прерывания, процессор должен найти процедуру его обработки и передать ей управление. Адрес этой процедуры (возможно, вместе с некоторой дополнительной информацией) хранится в определен­
    ном месте памяти и называется вектором прерывания. По нему и осуществ­
    ляется переход. Если компьютер различает несколько типов прерываний, в его памяти хранится список адресов процедур их обработки, называемый
    таблицей прерываний.
    Если таблица прерываний по каким-то причинам содержит неверную информацию, в ответ на прерывания возможны самые разнообразные ошибки. Если, например, векторы прерываний просто поменялись места­
    ми, программа может вести себя странно, пытаясь, например, отобразить на экране введенный символ в ответ на сигнал от системного таймера или реагировать на нажатия клавиш как на сигналы тайм-аута.
    Приложение: Распространенные программные ошибки 5 0 7
    Ошибки, связанные с модификацией программами таблицы
    прерываний
    Программа может модифицировать таблицу прерываний, записав в нее новые адреса. Если это делается на время работы определенного модуля, перед завершением он должен восстановить исходные векторы прерываний.
    Возможно также, что программа запишет в таблицу прерываний неверный адрес или вообще ее запортит. В результате после очередного прерывания компьютер перейдет не к той подпрограмме или вообще "зависнет".
    Ошибки, связанные с блокированием прерываний
    Программа может блокировать большинство прерываний, в результате чего компьютер перестает на них реагировать. Например, в некоторых случаях большая часть прерываний блокируется перед началом записи данных на диск и разблокируется после ее окончания. Это предотвращает многие ошибки передачи данных.
    Неудачное возобновление работы программы после прерывания
    Выполнение программы было прервано, а затем возобновлено. В неко­
    торых системах после возобновления программа получает сообщение или иное указание, что она была прервана. В сообщении обычно указывается тип прерывания (от клавиатуры, таймера, модема и т.п.). Это очень полез­
    но. Например, программа может обновить изображение на экране, предпо­
    лагая, что в ходе обработки прерывания оно могло быть изменено. Однако во встроенном в программу блоке обработки прерывания программист может допустить ошибку, например, передать дальнейшее управление не той подпрограмме. С ошибками такого рода программисты так же не лю­
    бят иметь дело, как и с ошибками в блоках обработки ошибок, и так же часто их пропускают.
    Завершение работы программы
    Некоторые языки программирования останавливают программу, когда в ней происходят ошибки определенных типов. Бывает также, что ни язык программирования, ни программист не предполагали остановки програм­
    мы, но она все же останавливается.
    Не каждое прекращение работы программы происходит вследствие ошибки, связанной с управлением потоком. Если завершение работы при определенном условии определяется программным кодом и программа завершается неожиданно для пользователя, значит, речь идет об ошибке пользовательского интерфейса.

    5 0 8 Часть III: Управление проектами и группами
    "Зависание" компьютера
    "Зависнув", компьютер прекращает реагировать на клавиатурный и иной ввод, прекращает печатать, индикаторы не меняют своего состояния, но при этом могут и гореть. Единственным способом, позволяющим вос­
    становить работоспособность системы, является аппаратный перезапуск компьютера (выключение и включение питания или нажатие кнопки Reset).
    Как правило, причиной "зависания" компьютера становятся бесконеч­
    ные циклы. Если операционная система позволяет прикладным програм­
    мам полностью захватывать управление, программа может, например, бесконечно ждать ответа какого-либо устройства. Если же операционная система не позволяет программам блокировать компьютер, у пользователя остается возможность выгрузить "зависшую" программу из памяти без перезапуска компьютера и не повредив работе остальных активных прило­
    жений.
    Синтаксические ошибки, сообщения о которых
    отображаются во время выполнения
    программы
    Если программа написана на интерпретируемом языке программирова­
    ния, синтаксическая проверка ее текста может не выполняться до тех пор, пока программа не будет запущена. Интерпретатор по очереди анализирует и выполняет каждую команду программы. Наткнувшись на команду, не поддающуюся интерпретации, он выводит на экран сообщение об ошибке и останавливает программу. Виновницей ситуации оказывается команда, которая содержит синтаксическую ошибку. Очевидно, что программист ни разу не выполнил данный фрагмент кода.
    Ожидание невозможных условий или
    комбинаций условий
    Программа останавливается ("зависает") в ожидании события, которое никогда не наступит. Вот несколько распространенных примеров.
    Проблемы ввода/вывода. Компьютер посылает данные поломанному выходному устройству и бесконечно ждет его ответа. Подобная си­
    туация возможна и при обмене данными между двумя процессами, когда один процесс посылает сообщение другому и ждет его ответа, а тот почему-либо не отвечает.
    Взаимная блокировка. Это классическая проблема многозадачных систем. Две программы работают параллельно. Обеим нужна одна и та же пара ресурсов (скажем, принтер и дополнительная память под буфер печати). Программы захватывают по одному ресурсу и ждут, пока освободится второй.
    Приложение: Распространенные программные ошибки 5 0 9
    Простая логическая ошибка. Например, программа должна вводить числа от 1 до 5, отвергая любые другие данные. Однако в ней зап­
    рограммировано следующее условие допустимости числа:
    IF INPUT > 5 AND INPUT < 1. Такому условию не соответствует вообще ни одно число, поэтому программа отвергает любой ввод и ждет бесконечно долго.
    Подобным же образом в многозадачной системе один процесс может бесконечно долго ждать получения от другого невозможных данных.
    Неверный приоритет пользователя или
    процесса
    В системах с приоритетной многозадачностью компьютер, параллельно выполняющий несколько программ, периодически переключается между ними. Он некоторое время выполняет одну программу, затем переключа­
    ется к другой, некоторое время выполняет ее, затем переключается к тре­
    тьей и т.д. по кругу. Переключение к определенной программе выполняется в случае, когда наступило связанное с ней событие (например, пользова­
    тель нажал клавишу) или она просто ждет слишком долго. Если две про­
    граммы ждут одинаково долго, активизируется та, приоритет которой выше.
    (Приоритет назначается системой либо самой программе, либо ее пользо­
    вателю.)
    В такой системе задача с низким приоритетом может ожидать своей очереди выполнения несколько часов. Иногда так и должно быть, но воз­
    можно, что приоритет просто неправильно назначен. Если задержки в выполнении программы не столь очевидны, ошибку, связанную с непра­
    вильным назначением приоритета, крайне трудно заметить, если только она не приведет к ситуации гонок.
    Циклы
    Существует несколько разновидностей программных циклов, но все они очень схожи. Вот пример.
    1 SET LOOP_CONTROL = 1 2 REPEAT
    3 SET VAR = 5 4 PRINT VAR * LOOP-CONTROL
    5 SET LOOP_CONTROL = LOOP_CONTROL +1 6 UNTIL LOOP_CONTROL >5 7 PRINT VAR
    Программа присваивает переменной LOOP_CONTROL значение 1, переменной VAR значение 5, печатает произведение значений этих двух переменных, увеличивает значение LOOP_CONTROL на 1 и затем прове­
    ряет, не превысило ли ее значение число 5. Поскольку значением

    5 1 0 Часть III: Управление проектами и группами
    LOOP_CONTROL пока является 2, программа повторяет код тела цикла
    (команды 3, 4 и 5). Так продолжается до тех пор, пока переменная
    LOOP_CONTROL не получит значение 6. После этого программа перехо­
    дит к следующей за циклом команде (ее номер 7) и печатает значение переменной VAR.
    Переменную LOOP_CONTROL называют переменной управления циклом. Ее значение определяет, сколько раз выполнится тело цикла. Для управления циклом не обязательно используется одна переменная, неред­
    ко после ключевого слова UNTIL стоит целое выражение, включающее целый ряд переменных. Но в обоих случаях возможны одни и те же ошиб­
    ки.
    Бесконечный цикл
    Если условие выхода из цикла никогда не наступает, программа может выполнять составляющие его команды бесконечно. Такая ситуация назы­
    вается зацикливанием. Если модифицировать вышеприведенный фрагмент кода таким образом, чтобы цикл выполнялся, пока значение переменной
    LOOP_CONTROL не станет меньше 0, этот цикл никогда не завершится.
    Неверное начальное значение переменной
    управления циклом
    Предположим, что в вышеприведенной программе далее стоит оператор
    GOTO, передающий управление команде в строке 2. Переменная
    LOOP_CONTROL может иметь теперь какое угодно значение. Если про­
    граммист предполагал, что тело цикла будет выполнено пять раз (как если бы переход был выполнен не ко второй, а к первой строке), он может быть очень удивлен происходящим.
    Случайное изменение переменной управления
    циклом
    В вышеприведенном примере значение переменной LOOP_CONTROL изменяется внутри цикла. В более длинном цикле, особенно если из него вызываются другие подпрограммы, имеющие доступ к переменной
    LOOP_CONTROL, ее значение может изменяться в нескольких местах программы, так что в результате тело цикла выполнится больше или мень­
    ше раз, чем задумал программист.
    Ошибочный критерий выхода из цикла
    Возможно, цикл должен завершиться при условии LOOP_CONTROL
    >= 5, а не LOOP_CONTROL > 5. Это очень распространенная ошибка. А если критерий выхода из цикла достаточно сложен, в нем может быть даже несколько ошибок.
    Приложение: Распространенные программные ошибки 5 1 1
    Команды, которые должны или не должны
    выполняться внутри цикла
    В вышеприведенном примере команда SET VAR = 5 помещена внутрь цикла. Но поскольку значение переменной VAR в ходе выполнения про­
    граммы не меняется, присвоение ей значения 5 на каждом проходе цикла является пустой потерей времени. Некоторые циклы выполняются тысячи и миллионы раз, и тогда ненужные повторения могут серьезно отразиться на производительности программы.
    Вот если бы значение переменной VAR менялось в ходе выполнения цикла и перед каждым повторением его команд эта переменная должна была бы снова принимать исходное значение, тогда данная команда при­
    сваивания была бы необходима именно внутри цикла, а не перед ним.
    Ошибка вложенности циклов
    Один цикл может быть вложен в другой, т.е. полностью включен внутрь него. В этом случае, если только программист не допустил ошибку, невоз­
    можно, чтобы цикл начался внутри другого цикла, а завершился вне него.
    Условные операторы
    Условный оператор (оператор IF) имеет следующую форму.
    IF Условие истинно
    THEN
    1   ...   41   42   43   44   45   46   47   48   49


    написать администратору сайта