Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:
5.2. Источники ошибок
• Плохая спецификация. Если мы слабо представляем себе, что должна делать программа, то вряд ли сможем адекватно проверить все ее “темные углы” и убедиться, что все варианты обрабатываются правильно (т.е. что при любом входном наборе данных мы получим либо правильный ответ, либо осмысленное сообщение об ошибке).
• Неполные программы. В ходе
• Непредусмотренные аргументы. Функции принимают аргументы. Если функция принимает аргумент, который не был предусмотрен, то возникнет проблема, как, например, при вызове стандартной библиотечной функции извлечения корня из –1,2:
• Непредусмотренные входные данные. Обычно программы считывают данные (с клавиатуры, из файлов, из средств графического пользовательского интерфейса, из сетевых соединений и т.д.). Как правило, программы выдвигают к входным данным много требований, например, чтобы пользователь ввел число. А что, если пользователь введет не ожидаемое целое число, а строку “Отстань!”? Этот вид проблем обсуждается в разделах 5.6.3 и 10.6.
• Неожиданное состояние. Большинство программ хранит большое количество данных (“состояний”), предназначенных для разных частей системы. К их числу относятся списки адресов, каталоги телефонов и данные о температуре, записанные в объекты типа
• Логические ошибки. Эти ошибки приводят к тому, что программа просто делает не то, что от нее ожидается; мы должны найти и исправить эти ошибки. Примеры поиска таких ошибок приводятся в разделе 6.6 и 6.9.
Данный список имеет практическое применение. Мы можем использовать его для контроля качества программы. Ни одну программу нельзя считать законченной, пока не исследованы все потенциально возможные источники ошибок. Этот список целесообразно иметь в виду уже в самом начале проекта, поскольку очень маловероятно, что поиск и устранение ошибок в программе, запущенной на выполнение без предварительного анализа, не потребует серьезной переработки.
5.3. Ошибки во время компиляции
Когда вы пишете программы, на первой линии защиты от ошибок находится компилятор. Перед тем как приступить к генерации кода, компилятор анализирует его в поисках синтаксических ошибок и опечаток. Только если компилятор убедится, что программа полностью соответствует спецификациям языка, он разрешит ее дальнейшую обработку. Многие ошибки, которые обнаруживает компилятор, относятся к категории “грубых ошибок”, представляющих собой ошибки, связанные с типами, или результат неполного редактирования кода.
Другие ошибки являются результатом плохого понимания взаимодействия частей нашей программы. Новичкам компилятор часто кажется маловажным, но по мере изучения свойств языка — и особенно его системы типов — вы по достоинству оцените способности компилятора выявлять проблемы, которые в противном случае заставили
В качестве примера рассмотрим вызовы следующей простой функции:
5.3.1. Синтаксические ошибки
Что произойдет, если мы вызовем функцию area следующим образом:
Каждая из этих строк содержит синтаксическую ошибку; иначе говоря, они не соответствуют грамматике языка С++, поэтому компилятор их отклоняет. К сожалению, синтаксические ошибки не всегда можно описать так, чтобы программист легко понял, в чем дело. Это объясняется тем, что компилятор должен проанализировать немного более крупный фрагмент текста, чтобы понять, действительно ли он обнаружил ошибку. В результате даже самые простые синтаксические ошибки (в которые даже невозможно поверить) часто описываются довольно запутанно, и при этом компилятор ссылается на строку, которая расположена в программе немного дальше, чем сама ошибка. Итак, если вы не видите ничего неправильного в строке, на которую ссылается компилятор, проверьте предшествующие строки программы.
Обратите внимание на то, что компилятор не знает, что именно вы пытаетесь сделать, поэтому формулирует сообщения об ошибках с учетом того, что вы на самом деле сделали, а не того, что намеревались сделать. Например, обнаружив ошибочное объявление переменной
“Вы неправильно написали слово
Скорее, он выразится так:
“Синтаксическая ошибка: пропущена
“У переменной
“Неправильный идентификатор класса или типа
Такие сообщения выглядят туманными, пока вы не научитесь их понимать и использовать. Разные компиляторы могут выдавать разные сообщения, анализируя один и тот же код. К счастью, вы достаточно скоро научитесь понимать эти сообщения без каких-либо проблем. В общем, все эти зашифрованные сообщения можно перевести так:
“Перед переменной
Поняв это, уже нетрудно решить проблему.
ПОПРОБУЙТЕ
Попробуйте скомпилировать эти примеры и проанализируйте ответы компиляторов.
5.3.2. Ошибки, связанные с типами
После того как вы устраните синтаксические ошибки, компилятор начнет выдавать сообщения об ошибках, связанных с типами; иначе говоря, он сообщит о несоответствиях между объявленными типами (или о типах, которые вы забыли объявить) ваших переменных, функций и так далее и типами значений и выражений, которые вы им присваиваете, передаете в качестве аргументов и т.д.