Можно выделить два типа ошибок, с которыми сталкивается программист. Во-первых - это ошибки, которые сопровождают создание программ, а во вторых -
Если вы неправильно введете оператор или ключевое слово, если забудете указать часть выражения - ошибка сразу же будет заметна в редакторе. Такие ошибки относятся к
Приведем несколько примеров
For-Next сделать ошибку в ключевом слове For - вы увидите сообщение об ошибке как только попытаетесь перейти к написанию следующей, после начала цикла, строки.Dim при объявлении переменной - редактор выдаст сообщение об ошибке. Однако, сделает он это лишь при попытке запуска программы.А вот -
Str для получения строкового представления числа, вы не учли, что для положительных чисел эта функция добавляет в начало строки пробел. Далее вы попытались узнать первую цифру числа, вырезав первый символ полученной строки. Естественно, никакой цифры в этом случае не получится - лишь знак пробела для положительных или "минус" для отрицательных чисел.i, вторая - j. Они довольно сильно похожи внешне, их можно случайно перепутать при указании индексов массива. К тому же, обрабатывая массив в цикле довольно легко перепутать место каждой из переменных при указании my_Age или num_Vozrast для хранения возраста и т.д.) позволяет эффективно бороться с такими ошибками.num_Inp, а использовав эту переменную в выражении, напечатали не num_Inp, а num_Ihp. Внешне они похожи, но, присмотревшись, вы можете обнаружить, что имена разные. Еще сложней искать ошибки в латинских именах переменных, в которые "вкрались" русские буквы. Разницу между my_Name и my_Namе вы не увидите, но это - разные переменные - в конце второй вместо латинской e использована русская е. Эффективно бороться с такими ошибками можно, если задать в редакторе опцию обязательного объявления переменных ( Option Explicit ). При появлении необъявленной переменной редактор даст знать об этом.< вы случайно использовали > или, редактируя сравнение (скажем, скопировав похожий оператор сравнения из другого места программы для ускорения работы), поменяли местами сравниваемые переменные или выражения, не поменяв знака и т.д.Ошибки логики можно найти лишь тщательно проверив и протестировав программу. Чтобы облегчить работу с кодом программы, рекомендуется снабжать ее комментариями. Вовсе необязательно комментировать каждую строчку, достаточно выделить крупные функциональные блоки.
Такие ошибки называют еще
Давайте, для начала, рассмотрим способы поиска ошибок в процессе создания программ
Для начала протестируйте вашу программу в обычном режиме работы. Например, если вы предлагаете ввести пользователю число - введите сами число и проверьте результаты работы. Если действия программы будут различаться в зависимости от введенных данных - попытайтесь перебрать все варианты этих данных - так, чтобы проверить все ветви программы.
Если обычные проверки закончились успешно - можно считать, что ваша программа корректно работает, не имеет
После этого можно усложнить режим тестирования, чтобы как можно более полно сымитировать действия пользователя программы и посмотреть на ее поведение. Еще лучше - попытайтесь целенаправленно вызвать ошибку. Гораздо лучше, когда программа даст сбой на вашем рабочем столе, и вы сможете оперативно устранить этот сбой, чем ждать, когда то же самое произойдет у другого пользователя.
Для проверки программы в реальных условиях попробуйте провести следующие эксперименты.
Selection в MS Word, который чувствителен к смене выделения в процессе работы, и объект Range, который может работать совсем без создания выделения в тексте.Возможно, вам покажется, что такая проверка не нужна вашей программе. Если вы пишете небольшой макрос для собственного использования, скорее всего, так оно и есть. Но стоит вашему проекту хоть немного вырасти, методы поиска и устранения ошибок могут оказаться очень кстати.
Если вы встретитесь с ошибками и затрудняетесь определить, где именно они происходят - попробуйте выполнить программу в пошаговом режиме, используйте встроенные в редактор VBA средства для
Основной метод отладки - это
Чтобы создать в программе точку останова, достаточно щелкнуть мышью в редакторе на серой панели напротив команды, на которой нужно остановить выполнение программы. Там появится большая красная точка (рис. 8.1.) - здесь программа будет остановлена в процессе выполнения. Строка будет подсвечена красным цветом.
(рис 8.1) Точка останова в программе Следует понимать, что строка, подсвеченная при остановке программы еще не выполнялась - редактор указывает на нее, как бы говоря "Эта строка будет выполнена следующей".
Таких точек останова можно установить столько, сколько нужно - на тех строках программы, где вы подозреваете возникновение ошибки. Чтобы убрать точку останова, щелкните по ней мышью.
Установить точку останова в строку можно, выделив строку и выбрав команду Debug o Toggle Breakpoint (Отладка o Установить точку останова). Для удаления всех точек останова из программы можно воспользоваться командой Debug o Clear All Breakpoints (Отладка o Очистить точки останова).
Вместо точек останова, расставленных мышью или из меню, можно использовать оператор Stop. Он останавливает работу программы и переводит ее в режим
Так же режим и нажав в появившемся окне кнопку Debug. Текущая строка будет выделена желтым цветом, напротив нее будет установлена желтая стрелочка. Однако такой способ обычно не позволяет точно "попасть" в то место программы, где находится предполагаемая ошибка (рис. 8.2.).
(рис 8.2) Программа, остановленная во время выполнения Чтобы запущенная программа останавливалась на каждой строке, можно запустить ее в режиме Step Into командой Debug o Step Into (Отладка o Пошаговое исполнение). Того же эффекта можно достичь, нажав клавишу F8 на клавиатуре.
Когда программа остановлена, вы можете выполнить следующие действия
Помимо режима Step Into существуют следующие режимы отладки, доступные в меню Debug.
Помимо точек останова существуют и другие средства
08-01-Работа с Immediate.docm - пример к п. 8.5.
Окно Immediate (Немедленное выполнение) представляет собой нечто вроде "филиала" редактора кода. Чтобы отобразить его, можно воспользоваться командой View o Immediate Window (Вид o Окно непосредственных изменений). С помощью Immediate можно мгновенно выполнять различные команды, вызывать процедуры и функции - как пользовательские, так и встроенные. Так же в него можно организовать вывод различных данных в ходе выполнения программы. Давайте рассмотрим основные возможности этого окна.
Для отправки в окно Immediate информации из выполняющейся программы нужно воспользоваться такой конструкцией:
Debug.Print
Метод Print объекта Debug организует вывод в Immediate. После того, как выполнение программы завершится, вы сможете проанализировать выведенные данные.
Например, добавим в VBA-проект форму, назовем ее frm_Test, на форму добавим кнопку - cmd_Test. Добавим в код обработчика нажатия кнопки такой код (листинг 8.1.):
Dim TwoDim(4, 5)
Dim OneDim(30)
Dim num_Transfer
For i = 0 To 4
For j = 0 To 5
TwoDim(i, j) = Int(Rnd * 100)
Next j
Next i
For i = 0 To 4
Debug.Print ("i=" + Str(i))
For j = 0 To 5
num_Transfer = num_Transfer + 1
OneDim(num_Transfer) = TwoDim(i, j)
Debug.Print ("j=" + Str(j))
Debug.Print ("OneDim" + Str(num_Transfer) + _
" =" + Str(OneDim(num_Transfer)))
Debug.Print ("TwoDim" + Str(i) + Str(j) + _
" =" + Str(TwoDim(i, j)))
Next j
Next i
Здесь мы объявили два массива - один двумерный ( TwoDim ), второй одномерный ( OneDim ). Заполнили TwoDim случайными числами, после чего организовали перенос данных из него в OneDim. В циклическую конструкцию, которая осуществляет перенос данных, мы вставили несколько вызовов Debug.Print. Они позволили нам получить полную картину работы этого блока в окне Immediate (рис. 8.4.).
Подобный же метод может быть весьма полезен, например, при проверке алгоритма сортировки и любых других сложных алгоритмов.
(рис 8.4) Окно Immediate после вывода значений На рис. 8.5. вы можете видеть окно Immediate, которое содержит несколько команд. Эти команды мы вводили в режиме останова программы из листинга 8.1.
(рис 8.5) Работа с Immediate в режиме останова Команда ?. Если вы программировали на обычном Basic'e, этот значок должен быть вам хорошо знаком.
Командой ? 25*14-4+11^7 мы вычисляем введенное выражение.
Командой ? TwoDim(1, 1) мы выводим число, хранящееся в TwoDim(1, 1). В нашем случае это 76. После этого мы записываем команду TwoDim(1, 1)=11, тем самым присваивая элементу массива новое значение, и выводим это значение снова.
Теперь рассмотрим возможности по запуску процедур и функций. Создадим в коде формы простую процедуру с именем hello, которая выводит окно сообщения с текстом "Привет". Чтобы вызывать эту процедуру, не выполняя программу, достаточно ввести в окно Immediate такой код: frm_Test.hello. Вот, как выглядит окно после ввода команды (рис. 8.6.).
(рис 8.6) Окно кода с пользовательской процедурой и Immediate после ввода команды После нажатия на кнопку Enter процедура будет выполнена и окно сообщения покажется на экране. Таким способом можно проверять работу процедур, отлаживать их до включения их в основной код программы.
Как видите, Immediate - это очень простое, но мощное средство
Окно Locals (Локальные переменные) позволяет просматривать и изменять свойства всех объектов приложения и значения переменных. Посмотрите, как выглядит окно Locals при открытии его в режиме останова программы, с которой мы работали в п. 8.5. (рис. 8.7.)
(рис 8.7) Окно Locals открытое при останове программы Как видите, здесь есть объект Me, который представляет собой форму, массивы, объявленные в коде, переменные. Для посмотра или редактирования свойств объектов и содержимого массивов, достаточно развернуть их описания, нажав на знак + перед их наименованиями. Для редактирования значения нужно просто выделить его и ввести вместо старого новое. Учтите, что строковые значения нужно вводить в кавычках - так же, как и в программном коде.
Окно Watches (Контролируемые выражения) предназначено для контроля за отдельными выражениями, значениями переменных и т.д.
Чтобы добавить такое выражение, щелкните мышью по нему и выберите команду меню Add Watch (Контролировать). Появится окно Add Watch (рис. 8.8.).
(рис 8.8) Окно Add Watch Здесь, в поле Expression (Выражение) нужно ввести контролируемое выражение. В нашем случае это имя переменной.
В группе параметров Context (Контекст) следует выбрать область контроля. Чем эта область меньше (в нашем случае - это процедура cmd_Test_Click, которая хранится в модуле формы frm_Test ) - тем лучше.
В группе параметров Watch type (Тип наблюдения) нужно выбрать тип наблюдения за выражением.
Watch Expression (Наблюдать за выражением) - программа просто выводит в окно Watch значение наблюдаемого выражения, ничего не предпринимая. Если вы перейдете в режим
Break When Value Is True (Прервать работу программы если выражение выполняется) - при выполнении определенного в окне Add Watch условия программа остановится и перейдет в режим num_Transfer > 100 и активируем данный пункт, то работа программы будет остановлена лишь тогда, когда значение переменной num_Transfer превысит 100.
Break When Value Changes (Прервать работу программы при изменении значения) - прерывает выполнение программы если значение контролируемой переменной или выражения изменилось. Если мы сделаем эту опцию активной, при каждом изменении переменной программа будет переходить в режим num_Transfer мы попадем в режим
(рис 8.9) Работа с окном Watches в режиме отладки Как видите, в окне Watches отображены следующие данные:
При необходимости вы можете отредактировать контролируемое выражение - для этого щелкните правой кнопкой мыши по строке выражения в окне Watches и выберите пункт Edit Watch. Для удаления выражения выберите в том же меню пункт Delete Watch, для добавления нового - Add Watch.
08-02-Проверка введенных даных.docm - пример к п. 8.8.
Для проверки данных, вводимых пользователем, вы можете воспользоваться стандартными конструкциями для принятия решений.
Давайте рассмотрим пример, в котором пользователь должен ввести свой возраст в ответ на запрос программы. Очевидно, что возраст должен удовлетворять следующим условиям.
Byte - то есть введенное значение не может быть больше 256 и меньше 0.Так же мы ограничим количество возможных попыток для ввода возраста тремя.
Добавим в документ Microsoft Word две кнопки. Одну из них назовем cmd_AgeInput и подпишем как Введите ваш возраст, вторую назовем cmd_InpAge_Easy и подпишем как Простой ввод возраста.
Для проверок создадим несколько пользовательских функций, реализующих их. Такой подход очень удобен, так как позволяет уменьшить количество сложночитаемых вложенных конструкций If-Then-Else и делает работу с программой и ее
В листинге 8.2. приведена функция, которая проверяет, соответствует ли введенное число нашим требованиям.
Public Function IsGoodNum(var_Inp) As Boolean
'Функция возвращает True, если введенное
'число подходит, иначе - False
If IsNumeric(var_Inp) = True _
And Val(var_Inp) > 0 _
And Val(var_Inp) < 255 _
Then
IsGoodNum = True
Else
IsGoodNum = False
End If
End Function
В листинге 8.3 вы можете найти функцию, которая проверяет введенное число и возвращает True, если оно больше 100.
Public Function IsMore100(var_Inp) As Boolean
'Функция возвращает True, если введенное число
'более 100
If Val(var_Inp) > 100 Then
IsMore100 = True
Else
IsMore100 = False
End If
End Function
В листинге 8.4. вы можете найти код функции, которая возвращает строку с описанием ошибки, которую допустил пользователь при вводе возраста.
Public Function NotNumber(var_Inp) As String
'Определяет, что именно ввел пользователь
'вместо ожидаемого числа и возвращает
'строку для вывода сообщения об ошибке
'Если не выполнится ни одно из условий
'программа выдаст общее сообщение об
'ошибке ввода данных
NotNumber = "Ошибка ввода данных"
'Если ей удастся определить тип ошибки
'будет выведено более точное сообщение
If var_Inp = "" Then
NotNumber = "Вы забыли ввести возраст"
End If
If Val(var_Inp) < 0 Then
NotNumber = "Вы ввели отрицательное число"
End If
If IsNumeric(var_Inp) = False Then
NotNumber = "Вы ввели не число"
End If
If Val(var_Inp) > 255 Then
NotNumber = "Вы ввели слишком большое число"
End If
End Function
Листинг 8.5 содержит текст программы, которая использует вышеописанные функции для проверки введенного пользователем возраста.
Private Sub cmd_AgeInput_Click()
'Переменная для ввода пользователм
Dim str_Inp
'Сюда запишем возраст после проверки
Dim num_Age As Byte
'А здесь будем хранить ответ пользователя на
'Вопрос о том, уверен ли он в том, что ему
'Больше 100 лет
Dim IsYouMore100 As Variant
'В этой переменной будем хранить количество
'Неправильных попыток ввода
'Если оно превысит 3 - выходим из программы
Dim num_InpTry As Byte
'Эта переменная нужна для того, чтобы
'определить, окончен ли опрос пользователя
Dim bool_Flag As Boolean
bool_Flag = False
'Этот цикл будет длиться до тех пор,
'пока пользователь не введет верное значение
'или пока не совершит максимальное число
'попыток
Do
str_Inp = InputBox("Введите ваш возраст")
If num_InpTry > 3 Then
MsgBox "Вы совершили более 3 ошибок"
Exit Sub
End If
num_InpTry = num_InpTry + 1
'Если введенное число подходит
If IsGoodNum(str_Inp) = True Then
'Проверяем - не больше ли оно 100
If IsMore100(str_Inp) = False Then
'Если не больше - просто устанавливаем
'флаг выхода в True
'и записываем возраст в переменную num_Age
bool_Flag = True
num_Age = CByte(str_Inp)
Else
'Если возраст больше 100 - переспросим
IsYouMore100 = _
MsgBox("Вам точно больше 100?", vbYesNo)
'Если пользователь не ошибся,
'Установим флаг выхода
'и запишем возраст в num_Age
If IsYouMore100 = vbYes Then
bool_Flag = True
num_Age = CByte(str_Inp)
End If
End If
Else
'Если пользователь изначально ввел
'неподходяще число,
'сгенерируем с помощью функции NotNumber
'сообщение об ошибке и выведем его
MsgBox (NotNumber(str_Inp))
End If
Loop Until bool_Flag = True
MsgBox ("Ваш возраст: " + Str(num_Age))
End Sub
Как видите, обычная проверка возраста пользователя оказывается не слишком простым делом. Однако серьезная программа не может обойтись без подобных проверок. Конечно же, возможны варианты проверки. Например, чтобы проверить возраст, и если он нас не устраивает, без дополнительных сообщений предложить пользователю снова ввести его, достаточно такой конструкции (листинг 8.6.):
Private Sub cmd_InpAge_Easy_Click()
Dim str_Inp
Dim num_Age As Byte
'Цикл продолжается до тех пор,
'пока введенное значение не станет
'числом, находящимся в диапазоне от
'0 (не включая 0) до 100
Do
str_Inp = _
InputBox("Введите ваш возраст")
Loop Until _
IsNumeric(str_Inp) = True _
And Val(str_Inp) <= 100 _
And Val(str_Inp) > 0
'Конвертируем введенное число в
'тип данных Byte
num_Age = CByte(Val(str_Inp))
MsgBox ("Ваш возраст: " + Str(num_Age))
End Sub
Как видите, здесь мы ограничились тройной проверкой на выходе из
08-03-Ошибки времени выполнения.docm - пример к п. 8.9.
Выше мы рассмотрели метод борьбы с ошибками, который заключался в их предотвращении. Но что делать, если в ходе работы программы происходит ошибка, для предотвращения которой ничего сделано не было?
В этой ситуации нам поможет перехват и обработка
Давайте рассмотрим ситуацию, которая гарантированно вызовет ошибку - деление на 0. Добавим в документ Microsoft Word кнопку с именем cmd_SimpleInput, подпишем ее как Отсутствие перехвата ошибок.
Напишем простую программу (поместив ее в обработчик события Click кнопки cmd_SimpleInput ), которая запрашивает у пользователя два числа, делит одно на другое и выводит результат деления. Следующий код (листинг 8.7.) реализует эту функциональность:
Dim num_A
Dim num_B
Dim num_C
num_A = InputBox("Введите число A")
num_B = InputBox("Введите число B")
num_C = num_A / num_B
MsgBox ("А, деленое на В равняется: " + Str(num_C))
Чтобы организовать обработку ошибок в программе нужно расположить перед потенциально опасным участком (в нашем случае - перед строкой, где происходит деление) оператор такого вида:
On Error GoTo Идентификатор_обработчика
Идентификатор обработчика ошибок - это номер или (что предпочтительнее) метка строки в коде текущей процедуры, куда должно быть передано управление при возникновении ошибки. Обработчик ошибок должен находиться в текущей процедуре. Использовать в качестве идентификатора обработчика имя процедуры или функции нельзя
В обработчике можно исправить ошибку, предложить пользователю выполнить какие-то действия или просто вывести сообщение об ошибке и завершить работу программы. В обработчике ошибок можно использовать оператор - он возвращает управление в строку, в которой произошла ошибка.
После того, как опасный участок программы пройден, обработку ошибок желательно отключить - это можно сделать такой командой:
On Error GoTo 0
Так же при обработке ошибок можно пользоваться командой
On Error Resume Next
Эта команда подавляет вывод сообщения об ошибке, просто передавая управление в следующую, после ошибочной, строку.
Для работы с ошибками, возникающими при выполнении программы, существует специальный объект - . Он содержит информацию об ошибках
Метод Clear очищает информацию об ошибках в объекте .
Метод Raise позволяет сгенерировать ошибку, указав в качестве параметра ее номер и некоторые другие, необязательные, данные. Эта возможность полезна при тестировании программ, оснащенных обработчиками ошибок, чтобы разработчик мог произвольно генерировать те или иные ошибки.
Номера ошибок находятся в диапазоне 0 - 65535. В частности, номера 0 - 512 зарезервированы за системными ошибками, 513 - 65535 - за ошибками, коды которых пользователь может назначать самостоятельно.
Например, для вызова ошибки
Err.Raise (13)
Свойство Number содержит номер ошибки. Обычно этот номер используют для выбора действия в обработчике ошибок.
Свойство Description содержит текстовое описание ошибки
Научим нашу программу обрабатывать ошибки, которые могут возникать при вводе "неправильных" чисел. В нашем простом примере возможно возникновение как минимум трех различных ошибок
OK, не введя число в поле ввода. Это - ошибка №13 - "Несоответствие типов"Нужно учитывать так же, что чисто теоретически возможно возникновение ошибки, для которой мы не предусмотрели определенный раздел обработчика.
В результате этих рассуждений у нас получился такой код (листинг 8.8.), который мы разместим в обработчике события Click кнопки cmd_ErrHandler, подписанной как Обработка ошибок и размещенной в том же документе, что и вышеописанная кнопка
Dim num_A
Dim num_B
Dim num_C
num_A = InputBox("Введите число A")
num_B = InputBox("Введите число B")
On Error GoTo ErrHandler
'С этого момента начинаем наблюдение
'за ошибками
num_C = num_A / num_B
On Error GoTo 0
'Прекращаем наблюдение за ошибками
MsgBox ("А, деленое на В равняется: " + _
Str(num_C))
Exit Sub
ErrHandler: 'Начало обработчика ошибок
MsgBox ("Вызвана ошибка №" + _
Str(Err.Number) + " " + _
Err.Description)
Select Case Err.Number
Case 6:
'Overflow - переполнение
'обе переменные равны 0
MsgBox ("Вы ввели A и B = 0")
num_A = InputBox("Введите число A")
num_B = InputBox("Введите число B")
Case 11:
'Деление числа на 0
MsgBox ("Вы ввели B = 0")
num_B = InputBox("Введите число B")
Case 13:
'Type mismatch - несоответствие типов
'одно из чисел или оба - не числа
MsgBox ("Одно из чисел или оба - не числа")
num_A = InputBox("Введите число A")
num_B = InputBox("Введите число B")
Case Else:
'на случай возникновения
'непредусмотренной ошибки
num_A = InputBox("Введите число A")
num_B = InputBox("Введите число B")
End Select
Resume
End Sub
Обратите внимание на то, что перед меткой строки, с которой начинается обработчик мы поставили команду Exit Sub. Это сделано для того, чтобы программа, дойдя до последней строки своей основной части, не начала бы выполнять обработчик ошибок.
Перед опасной операцией деления мы поставили команду On Error GoTo ErrHandler - если при делении произойдет ошибка, будет вызван обработчик. Необязательно устанавливать эту команду строго перед опасной процедурой - мы можем поставить ее в любом месте программы до нее. После того, как опасный участок пройден - следует команда On Error GoTo 0 - она отключает слежение за ошибками.
Внутри обработчика мы, прежде всего, выводим окно сообщения, где указываем номер ошибки и описание - и то и другое получено с помощью соответствующих свойств объекта . Далее, мы используем номер, хранящийся в свойстве Number объекта , чтобы произвести различные действия в зависимости от ошибки. В частности, наша программа может определять три вида ошибок ввода, сообщать об этом пользователю и запрашивать ввод переменных. Для обработки других ошибок, которые могут возникнуть, создана ветвь Case Else.
Как видите, обработка
В этой лекции мы рассмотрели вопросы
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.