Файл: Технология раработки програмного обеспечения УП.pdf

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

 

 

 
 

106 

Остальные

 

участники

 

также

 

приобретают

 

опыт,

 

рассматривая

 

ошибки

 

и

 

стиль

 

программирования

 

других

 

программистов.

 

Наконец,

 

инспекция

 

является

 

способом

 

раннего

 

выявле-

ния

 

наиболее

 

склонных

 

к

 

ошибкам

 

частей

 

программы,

 

позво-

ляющим

 

сконцентрировать

 

внимание

 

на

 

этих

 

частях

 

в

 

процессе

 

выполнения

 

тестирования

 

на

 

ЭВМ

 

(один

 

из

 

принципов

 

тести-

рования

 

п.

 

6.2).

 

6.3.3 Список вопросов для выявления ошибок при 

инспекции 

Важной

 

частью

 

процесса

 

инспектирования

 

является

 

про-

верка

 

программы

 

на

 

наличие

 

общих

 

ошибок

 

с

 

помощью

 

списка

 

вопросов

 

для

 

выявления

 

ошибок.

 

Концентрация

 

внимания

 

в

 

предлагаемом

 

списке

 

на

 

рассмотрении

 

стиля,

 

а

 

не

 

ошибок

 

(во-

просы

 

типа

 

«Являются

 

ли

 

комментарии

 

точными

 

и

 

информа-

тивными?»

 

и

 

«Располагаются

 

ли

 

операторы

 

THEN/ELSE

 

и

 

DO/END

 

по

 

одной

 

вертикали

 

друг

 

под

 

другом?»)

 

представляет-

ся

 

неудачной.

 

Также

 

неудачным

 

представляется

 

и

 

наличие

 

не-

определенности

 

в

 

списке,

 

уменьшающее

 

его

 

полезность

 

(вопро-

сы

 

типа

 

«Соответствует

 

ли

 

текст

 

программы

 

требованиям,

 

вы-

двигаемым

 

при

 

проектировании?»).

 

Список,

 

приведенный

 

в

 

данном

 

разделе,

 

был

 

составлен

 

после

 

многолетнего

 

изучения

 

ошибок

 

программного

 

обеспечения.

 

В

 

значительной

 

мере

 

он

 

является

 

независимым

 

от

 

языка;

 

это

 

означает,

 

что

 

большинство

 

ошибок

 

встречается

 

в

 

любом

 

языке

 

программирования.

 

6.3.3.1 Ошибки обращения к данным 

1.

 

Существуют

 

ли

 

обращения

 

к

 

переменным,

 

значения

 

ко-

торым

 

не

 

присвоены

 

или

 

не

 

инициализированы?

 

Наличие

 

пере-

менных

 

с

 

не

 

установленными

 

значениями

 

 

наиболее

 

часто

 

встречающаяся

 

программная

 

ошибка,

 

она

 

возникает

 

при

 

раз-

личных

 

обстоятельствах.

 

Для

 

каждого

 

обращения

 

к

 

единице

 

данных

 

(например,

 

к

 

переменной,

 

элементу

 

массива,

 

полю

 

в

 

структуре)

 

попытайтесь

 

неформально

 

«доказать»,

 

что

 

ей

 

при-

своено

 

значение

 

в

 

проверяемой

 

точке.

 


background image

 

 

 
 

107 

2.

 

Не

 

выходит

 

ли

 

значение

 

каждого

 

из

 

индексов

 

за

 

грани-

цы,

 

определенные

 

для

 

соответствующего

 

измерения

 

при

 

всех

 

обращениях

 

к

 

массиву?

 

3.

 

Принимает

 

ли

 

каждый

 

индекс

 

целые

 

значения

 

при

 

всех

 

обращениях

 

к

 

массиву?

 

Нецелые

 

индексы

 

не

 

обязательно

 

явля-

ются

 

ошибкой

 

для

 

всех

 

языков

 

программирования,

 

но

 

пред-

ставляют

 

практическую

 

опасность.

 

4.

 

Для

 

всех

 

обращений

 

с

 

помощью

 

указателей

 

или

 

пере-

менных-ссылок

 

память,

 

к

 

которой

 

производится

 

обращение,

 

уже

 

распределена?

 

Наличие

 

переменных-ссылок

 

представляет

 

собой

 

ошибку

 

типа

 

«подвешенного

 

обращения».

 

Она

 

возникает

 

в

 

ситуациях,

 

когда

 

время

 

жизни

 

указателя

 

больше,

 

чем

 

время

 

жизни

 

памяти,

 

к

 

которой

 

производится

 

обращение.

 

Например,

 

к

 

такому

 

результату

 

приводит

 

ситуация,

 

когда

 

указатель

 

задает

 

локальную

 

переменную

 

в

 

теле

 

процедуры,

 

значение

 

указателя

 

присваивается

 

выходному

 

параметру

 

или

 

глобальной

 

перемен-

ной,

 

процедура

 

завершается

 

(освобождая

 

адресуемую

 

память),

 

а

 

программа

 

затем

 

пытается

 

использовать

 

значение

 

указателя.

 

Как

 

и

 

при

 

поиске

 

ошибок

 

первых

 

трех

 

типов,

 

попытайтесь

 

не-

формально

 

доказать,

 

что

 

для

 

каждого

 

обращения,

 

использую-

щего

 

переменную-указатель,

 

адресуемая

 

память

 

существует.

 

5.

 

Если

 

одна

 

и

 

та

 

же

 

область

 

памяти

 

имеет

 

несколько

 

псевдонимов

 

(имен)

 

с

 

различными

 

атрибутами,

 

то

 

имеют

 

ли

 

значения

 

данных

 

в

 

этой

 

области

 

корректные

 

атрибуты

 

при

 

об-

ращении

 

по

 

одному

 

из

 

этих

 

псевдонимов?

 

Ошибки

 

типа

 

некор-

ректных

 

атрибутов

 

у

 

псевдонимов

 

могут

 

возникнуть

 

при

 

ис-

пользовании

 

атрибута

 

DEFINED

 

или

 

базированной

 

памяти

 

в

 

PL/1,

 

оператора

 

EQUIVALENCE

 

в

 

Фортране,

 

глагола

 

REDEFINES

 

в

 

Коболе,

 

записей

 

с

 

вариантами

 

в

 

Паскале

 

или

 

объединений

 

(UNION)

 

в

 

языке

 

Си.

 

В

 

качестве

 

примера

 

можно

 

привести

 

программу

 

на

 

языке

 

Си,

 

содержащую

 

вещественную

 

переменную

 

A

 

и

 

целую

 

переменную

 

B.

 

Обе

 

величины

 

размеще-

ны

 

на

 

одном

 

и

 

том

 

же

 

месте

 

памяти

 

(т.е.

 

помещены

 

в

 

одно

 

и

 

то

 

же

 

объединение).

 

Если

 

программа

 

записывает

 

величину

 

A,

 

а

 

обращается

 

к

 

переменной

 

B,

 

то,

 

вероятно,

 

произойдет

 

ошибка,

 

поскольку

 

машина

 

будет

 

использовать

 

битовое

 

представление

 

числа

 

с

 

плавающей

 

точкой

 

в

 

данной

 

области

 

памяти

 

как

 

целое.

 


background image

 

 

 
 

108 

6.

 

Отличаются

 

ли

 

типы

 

или

 

атрибуты

 

переменных

 

вели-

чин

 

от

 

тех,

 

которые

 

предполагались

 

компилятором?

 

Это

 

может

 

произойти

 

в

 

том

 

случае,

 

когда

 

программа

 

на

 

PL/1

 

или

 

Коболе

 

считывает

 

записи

 

из

 

памяти

 

и

 

обращается

 

к

 

ним

 

как

 

к

 

структу-

рам,

 

но

 

физическое

 

представление

 

записей

 

отлично

 

от

 

описания

 

структуры.

 

Или

 

программа

 

на

 

языке

 

Си,

 

допускающем

 

произ-

вольные

 

преобразования

 

типов,

 

содержит

 

переменную-указа

-

тель

 

на

 

структуру

 

типа

 

T

1

,

 

инициализированную

 

указателем

 

на

 

структуру

 

типа

 

T

2

 

(не

 

наследуемую

 

от

 

T

1

).

 

7.

 

Существуют

 

ли

 

явные

 

или

 

неявные

 

проблемы

 

адреса-

ции,

 

если

 

в

 

машине

 

будут

 

использованы

 

единицы

 

распределе-

ния

 

памяти,

 

меньшие,

 

чем

 

единицы

 

адресации

 

памяти?

 

Напри-

мер,

 

в

 

PL/1

 

в

 

системе

 

IBM

 

S/370

 

битовые

 

строки

 

фиксирован-

ной

 

длины

 

не

 

обязательно

 

начинаются

 

с

 

границ

 

байтов,

 

а

 

адре-

сами

 

могут

 

быть

 

только

 

границы

 

байтов.

 

Аналогично,

 

в

 

языке

 

Си

 

размер

 

отдельных

 

полей

 

в

 

структуре

 

может

 

задаваться

 

в

 

би-

тах.

 

Если

 

программа

 

вычисляет

 

адрес

 

битового

 

поля

 

и

 

впослед-

ствии

 

обращается

 

к

 

нему

 

по

 

этому

 

адресу,

 

то

 

может

 

произойти

 

ошибочное

 

обращение

 

к

 

памяти.

 

Такое

 

же

 

положение

 

может

 

сложиться

 

при

 

передаче

 

подпрограмме

 

(процедуре)

 

битового

 

поля

 

в

 

качестве

 

аргумента.

 

8.

 

Если

 

используются

 

указатели

 

или

 

переменные-ссылки,

 

то

 

имеет

 

ли

 

адресуемая

 

память

 

атрибуты,

 

предполагаемые

 

ком-

пилятором?

 

Примером

 

несоответствия

 

атрибутов

 

может

 

слу-

жить

 

случай,

 

когда

 

указатель

 

PL/1,

 

по

 

которому

 

базируется

 

структура

 

данных,

 

имеет

 

в

 

качестве

 

значения

 

адрес

 

другой

 

структуры.

 

9.

 

Если

 

к

 

структуре

 

данных

 

обращаются

 

из

 

нескольких

 

процедур

 

или

 

подпрограмм,

 

то

 

определена

 

ли

 

эта

 

структура

 

одинаково

 

в

 

каждой

 

процедуре?

 

10.

 

Не

 

превышены

 

ли

 

границы

 

строки

 

при

 

индексации

 

в

 

ней?

 

11.

 

Существуют

 

ли

 

какие-нибудь

 

другие

 

ошибки

 

в

 

опера-

циях

 

с

 

индексацией

 

или

 

при

 

обращении

 

к

 

массивам

 

по

 

индексу?

 


background image

 

 

 
 

109 

6.3.3.2 Ошибки описания данных 

1.

 

Все

 

ли

 

переменные

 

описаны

 

явно?

 

Отсутствие

 

явного

 

описания

 

не

 

обязательно

 

является

 

ошибкой,

 

но

 

служит

 

общим

 

источником

 

беспокойства.

 

Так,

 

если

 

в

 

подпрограмме

 

на

 

Фор-

тране

 

используется

 

элемент

 

массива

 

и

 

отсутствует

 

его

 

описание

 

(например,

 

в

 

операторе

 

DIMENSION),

 

то

 

обращение

 

к

 

массиву

 

(например,

 

Х

 

=

 

А(1)),

 

будет

 

интерпретироваться

 

как

 

вызов

 

функции.

 

Последнее

 

приведет

 

к

 

тому,

 

что

 

машина

 

будет

 

пы-

таться

 

обработать

 

массив

 

как

 

программу.

 

Если

 

отсутствует

 

яв-

ное

 

описание

 

переменной

 

во

 

внутренней

 

процедуре

 

или

 

блоке,

 

следует

 

ли

 

понимать

 

это

 

так,

 

что

 

описание

 

данной

 

переменной

 

совпадает

 

с

 

описанием

 

во

 

внешнем

 

блоке?

 

2.

 

Если

 

не

 

все

 

атрибуты

 

переменной

 

явно

 

присутствуют

 

в

 

описании,

 

то

 

понятно

 

ли

 

их

 

отсутствие?

 

Например,

 

отсутствие

 

атрибутов,

 

считающееся

 

общепринятым

 

в

 

PL/1,

 

часто

 

является

 

источником

 

неожиданных

 

осложнений.

 

3.

 

Если

 

начальные

 

значения

 

присваиваются

 

переменным

 

в

 

операторах

 

описания,

 

то

 

правильно

 

ли

 

инициализируются

 

эти

 

значения?

 

Во

 

многих

 

языках

 

программирования

 

присвоение

 

начальных

 

значений

 

массивам

 

и

 

строкам

 

представляется

 

до-

вольно

 

сложным

 

и,

 

следовательно,

 

является

 

возможным

 

источ-

ником

 

ошибок.

 

4.

 

Правильно

 

ли

 

для

 

каждой

 

переменной

 

определены

 

длина,

 

тип

 

и

 

класс

 

памяти

 

(например,

 

STATIC,

 

AUTOMATIC,

 

BASED

 

или

 

CONTROLLED

 

в

 

PL/1;

 

AUTO,

 

CONST,

 

VOLATILE,

 

REGISTER,

 

STATIC

 

в

 

Си

 

и

 

т.д.)?

 

5.

 

Согласуется

 

ли

 

инициализация

 

переменной

 

с

 

ее

 

типом

 

памяти?

 

Например,

 

если

 

в

 

подпрограмме

 

на

 

Фортране

 

необхо-

димо

 

устанавливать

 

начальные

 

значения

 

переменной

 

каждый

 

раз

 

при

 

вызове

 

подпрограммы,

 

переменная

 

должна

 

быть

 

ини-

циализирована

 

в

 

операторе

 

описания,

 

отличном

 

от

 

оператора

 

DATA.

 

Если

 

в

 

PL/1

 

описывается

 

инициализация

 

величины

 

и

 

начальное

 

значение

 

необходимо

 

устанавливать

 

каждый

 

раз

 

при

 

вызове

 

процедуры,

 

то

 

для

 

этой

 

переменной

 

должен

 

быть

 

опре-

делен

 

класс

 

памяти

 

АUTОМАТIС,

 

а

 

не

 

STATIC.

 

6.

 

Есть

 

ли

 

переменные

 

со

 

сходными

 

именами

 

(например,

 

VOLT

 

и

 

VOLTS)?

 

Наличие

 

сходных

 

имен

 

не

 

обязательно

 

явля-


background image

 

 

 
 

110 

ется

 

ошибкой,

 

но

 

служит

 

признаком

 

того,

 

что

 

имена

 

могут

 

быть

 

перепутаны

 

где-нибудь

 

внутри

 

программы.

 

6.3.3.3 Ошибки вычислений 

1.

 

Имеются

 

ли

 

вычисления,

 

использующие

 

переменные

 

недопустимых

 

(например,

 

неарифметических)

 

типов

 

данных?

 

2.

 

Существуют

 

ли

 

вычисления,

 

использующие

 

данные

 

разного

 

вида?

 

Например,

 

сложение

 

переменной

 

с

 

плавающей

 

точкой

 

и

 

целой

 

переменной.

 

Такие

 

случаи

 

не

 

обязательно

 

явля-

ются

 

ошибочными,

 

но

 

они

 

должны

 

быть

 

тщательно

 

проверены

 

для

 

обеспечения

 

гарантии

 

того,

 

что

 

правила

 

преобразования,

 

принятые

 

в

 

языке,

 

понятны.

 

Это

 

особенно

 

важно

 

для

 

языков

 

со

 

сложными

 

правилами

 

преобразования

 

(например,

 

для

 

PL/1,

 

Си).

 

Например,

 

следующий

 

фрагмент

 

программы

 

на

 

PL/1:

 

DECLARE A BIT(1); 
A=1; 

определяет

 

значение

 

A

 

равным

 

битовому

 

0,

 

а

 

не

 

1.

 

Или

 

в

 

языке

 

Си

 

попытка

 

присвоить

 

переменной

 

с

 

плавающей

 

точкой

 

значе-

ние

 

1/2

 

даст

 

значение

 

0

 

(т.к.

 

1

 

и

 

2

 

имеют

 

целый

 

тип).

 

3.

 

Существуют

 

ли

 

вычисления,

 

использующие

 

перемен-

ные,

 

имеющие

 

одинаковый

 

тип

 

данных,

 

но

 

разную

 

длину?

 

Та-

кой

 

вопрос

 

справедлив

 

для

 

PL/1,

 

и

 

возник

 

он

 

из

 

этого

 

языка.

 

Например,

 

в

 

PL/1

 

результатом

 

вычисления

 

выражения

 

25

 

+

 

1/3

 

будет

 

5.333...,

 

а

 

не

 

25.333

… 

Аналогично,

 

в

 

языке

 

Си

 

присутст-

вуют

 

множество

 

данных

 

одного

 

типа,

 

но

 

имеющих

 

разную

 

дли-

ну.

 

Например,

 

это

 

целые

 

типы

 

(CHAR,

 

INT,

 

LONG,

 

SHORT,

 

INT64

 

и

 

т.д.),

 

вещественные

 

типы

 

(FLOAT,

 

DOUBLE,

 

LONG

 

DOUBLE)

 

и

 

т.д.

 

К

 

тому

 

же,

 

эти

 

типы

 

могут

 

быть

 

как

 

знаковыми

 

(SIGNED),

 

так

 

и

 

беззнаковыми

 

(UNSIGNED).

 

4.

 

Имеет

 

ли

 

результирующая

 

переменная

 

оператора

 

при-

сваивания

 

атрибуты,

 

описывающие

 

ее

 

с

 

меньшей

 

длиной,

 

чем

 

в

 

атрибутах

 

выражения

 

в

 

правой

 

части?

 

5.

 

Возможны

 

ли

 

переполнение

 

или

 

потеря

 

результата

 

во

 

время

 

вычисления

 

выражения?

 

Это

 

означает,

 

что

 

конечный

 

ре-

зультат

 

может

 

казаться

 

правильным,

 

но

 

промежуточный

 

ре-