Файл: Технология раработки програмного обеспечения УП.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.

Возможны

ли

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

или

потеря

результата

во

время

вычисления

выражения?

Это

означает,

что

конечный

ре-

зультат

может

казаться

правильным,

но

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

ре-