Пятница, 19.04.2024, 02:41
Приветствую Вас Гость | RSS

Лекции

Меню сайта
Форма входа
Категории раздела
ТАУ (Теория автоматического управления) [31]
лекции по ТАУ
Экология [151]
учебник
Бухгалтерский учет и налогообложение в строительстве [56]
Дементьев А.Ю. - Практическое пособие
Психология [104]
Пип
информатика [80]
с# Карли Ватсон
современные стулья [0]
новинки
Поиск

Главная » 2010 » Февраль » 11 » Отладка и обработка ошибок
00:20
Отладка и обработка ошибок
Отладка и обработка ошибок
Итак, к настоящему моменту вы познакомились с основами простого програм-
мирования на С#. Перед тем как переходить к рассмотрению объектно-ориентиро-
ванного программирования, которому посвящен следующий раздел книги, мы
остановимся на вопросах отладки кода на С# и обработки ошибок.
Ошибки в программе — это такая вещь, от которой никогда не удастся избавить-
ся. Независимо от того, насколько опытным является программист, у него всегда
будут проскальзывать ошибки; составной частью понятия "опытный программист"
как раз и является понимание этой неизбежности и готовности с ними бороться.
Конечно, существуют некоторые незначительные ошибки, которые не оказывают
влияния на ход выполнения приложения, такие, например, как ошибки в правопи-
сании выводимого текста и т. п. Кроме того, существуют очевидные ошибки, кото-
рые приводят к абсолютной невозможности использования приложения (их обычно
называют фатальными). К разряду фатальных ошибок относятся как простые ошиб-
ки, которые препятствуют компиляции программы (синтаксические ошибки), так
и более сложные ошибки, которые проявляются только в процессе выполнения
кода. Однако могут встречаться еще более тонкие ошибки. Например, написанное
приложение не сможет включить в базу данных запись, у которой отсутствует одно
из обязательных полей, или в случае возникновения каких-либо исключительных
обстоятельств включит в запись неверные данные. Ошибки, подобные этим, когда
некоторый изъян содержится в логике приложения, известны под названием
семантических ошибок (или ошибок в логике).
Очень часто вы будете узнавать о наличии тонких ошибок в ваших приложени-
ях тогда, когда пользователь пожалуется, что что-то работает неправильно. В ре-
зультате вам придется выполнить трассировку программы, чтобы определить,
в чем именно проблема и каким образом следует изменить код, чтобы он выполнял
те действия, для которых был предназначен.
В подобных ситуациях вы обнаружите, что возможности для отладки программ,
предоставляемые VS, могут оказать вам ни с чем не сравнимую помощь. В первой
части этой главы мы рассмотрим некоторые предлагаемые методики с точки зре-
ния их использования для решения наиболее распространенных проблем.
Кроме этого, мы изучим способы обработки ошибок, имеющиеся в С#. Это
позволит нам принимать соответствующие меры предосторожности в тех случаях,
когда появление ошибок наиболее вероятно, и создавать код, который окажется
в состоянии справляться с ошибками, могущими в противном случае стать фаталь-
ными. Такие способы представляют собой составную часть языка С#, а не отла-
дочные возможности VS, однако и в этом случае VS предлагает некоторые весьма
полезные инструменты.
134 Глава 7
Отладка в Visual Studio
Когда программы запускаются в отладочном режиме, происходит нечто боль-
шее, чем просто выполнение написанного кода. При отладке создается некоторая
символьная информация о приложении, которая позволяет VS быть в курсе того,
что именно происходит при выполнении каждой строки кода. Под символьной ин-
формацией понимается, например, информация, которая позволяет устанавливать
соответствие между именами, используемыми в исходном коде, и значениями, ко-
торые существуют в скомпилированном в машинные коды приложении, не содер-
жащем информации в удобной для чтения форме. Символьная информация
помещается в файлы с расширением .pdb, которые вы, вероятно, встречали в ди-
ректориях Debug на вашем компьютере. Эта информация позволяет выполнять
множество полезных действий, например:
• Передачу отладочной информации системе VS
• Просмотр (и редактирование) значений рабочих переменных
в процессе выполнения приложения
• Приостановку и продолжение выполнения программы
• Автоматическое прекращение выполнения программы
в заранее заданных точках
• Пошаговое выполнение программы (по одной строке кода за шаг)
• Отслеживание изменений содержимого переменных
в процессе выполнения приложения
• Изменение содержимого переменных в момент выполнения
• Осуществление тестовых вызовов функций
В настоящем разделе вы познакомитесь с этими методами, а также с их исполь-
зованием для определения участков кода, которые работают не так, как ожидается,
и внесения в них исправлений, т. е. для процесса, более известного под названием
"отладка".
Все эти методы разделены на две группы по тому, каким образом они могут
быть применены. Вообще говоря, процедура отладки заключается в том, чтобы
либо прекращать выполнение программы, либо сохранять информацию для после-
дующего анализа. В терминах VS приложение может находится либо в режиме вы-
полнения, либо в режиме останова (break mode), означающем, что нормальное
выполнение программы прервано. Сначала мы рассмотрим методы отладки програм-
мы без прекращения ее выполнения (методы периода выполнения, или нормаль-
ные методы).
Отладка без использования режима останова
(в нормальном режиме)
Одной из команд, которая используется нами на протяжении всей книги, явля-
ется функция consoie.writeLineO ^предназначенная для вывода текста на консоль.
В процессе разработки приложений эту функцию удобно использовать для уста-
новления обратной связи с целью получения дополнительной информации о вы-
полняемых операциях. Например:
Console.WriteLine("Вызываем функцию MyFuncC).");
MyFunc("Выполнение некоторых действий.");
Console.WriteLine("Выполнение функции MyFuncO завершено.*);
Отладка и обработка ошибок 135
Этот участок кода демонстрирует, каким образом можно получать дополнительную
Информацию О работе фуНКЦИИ MyFunc ().
Все это замечательно, однако такой прием может привести к тому, что выход-
ной поток на консоль окажется сильно засоренным. Поэтому существует альтерна-
тива: можно выводить текст в специально предназначенное для этого место —
окно Output (вывод) в VS.
Как вы помните, в главе 2 вы познакомились с окном Output, которое по умол-
чанию располагается в нижней части основнрго окна среды разработки VS, там
же, где располагается окно Task List (список
заданий). Вы также познакомились с выво-
дом в этом окне информации, относящейся
к компиляции и выполнению кода, включая
встретившиеся в процессе компиляции ошиб-
ки и т. п. Существует возможность исполь-
зовать это окно для вывода специальной
диагностической информации, которая мо-
жет записываться туда напрямую. Это окно
изображено на рисунке слева.
Обратите внимание, что у этого окна имеются три режима,
переход между которым осуществляется с помощью
раскрывающегося списка. Мы можем переключаться
между режимами Build (построение), Debug (отладка)
и Test Run (выполнение в тестовом режиме). В режимах Build
и Debug в окне показывается информация, относящаяся
соответственно к периоду компиляции или к периоду
выполнения. В данном разделе словосочетание "вывод
в окно Output" будет означать "вывод в окно Output,
находящееся в режиме Debug".
В качестве альтернативы мы можем создать файл регистрации (logging file),
в который информация будет добавляться по мере выполнения нашего приложе-
ния. Способы записи в этот файл очень напоминают способы записи текста в окно
Output, однако они требуют понимания особенностей доступа к файловой системе
из приложений на С#. На данном этапе мы не будем отвлекаться на методы досту-
па к файлам, поскольку нам и без того предстоит изучить большое количество
материала.
Вывод отладочной информации
Вывод текста в окно Output в процессе выполнения является очень простой за-
дачей. ДЛЯ ЭТОГО ДОСТаТОЧНО Заменить Обращения К фуНКЦИИ Console. WriteLine О
на соответствующий вызов для записи текста в нужное место. Существуют две
команды, которые можно использовать с этой целью:
• Debug.WriteLine()
• Trace.WriteLine()
Обе эти команды выполняются практически одинаково, за исключением одного
ключевого отличия. Первая их них работает только в том случае, если строится от-
ладочная версия приложения, а вторая будет работать и в окончательной версии
программы. В последнем случае Debug. WriteLine о даже не будет транслироваться,
136 Глава 7
а просто исчезнет, что, естественно, дает определенные преимущества (хотя бы то,
что откомпилированная программа будет меньше по объему). На самом деле мы
можем пользоваться двумя версиями одного приложения, создаваемыми из одного
и того же исходного файла. Отладочная версия выводит все виды диагностической
информации, в то время как основная версия не несет этой дополнительной на-
грузки и не выводит эти сообщения, способные сильно раздражать пользователя!
Следует обратить внимание, что работа этих функций несколько отличается от
работы функции console.writeLineO. Они работают только с одним строковым
параметром для вывода сообщения и не допускают вывода значений за счет ис-
пользования синтаксиса {х>. Это означает, что для включения численных значений
в выводимую строку необходимо использовать оператор +. Однако существует
возможность использовать второй строковый параметр (необязательный), который
применяется для указания категории выводимого текста. Категория позволяет
даже при беглом просмотре выходных сообщений в окне Output определять, с ка-
кими сообщениями мы имеем дело в тех случаях, когда похожие сообщения могут
выводиться из разных мест программы.
Вывод этих функций имеет следующий вид:
<категория>: <сообщение>
Например, следующий оператор в качестве дополнительного параметра, определя-
ющего категорию, использует параметр *myFuncff:
Debug.WriteLineCAdded 1 to i " , "myFunc") ;
Результат его выполнения будет следующий:
myFunc: Added 1 to i
Давайте рассмотрим пример.
Практикум: вывод текста в окно Output
1. Создайте новое консольное приложение с именем ch07Ex0i
В директории C:\BegCSharp\Chapter7.
2. Внесите следующие изменения в программу:
using System;
u s i n g S y s t e m * D i a g n o s t i c s ; •, •.;.:-'.: :'•'•".' :; •''••yy-y-4.^ . .... ;.' '.'44- • •'•;•'•••.''.' : ., .
namespace Ch07Ex01
/// <summary>
/// Summary description for Classl.
/// </summary>
class Classl
static void Main(string[] args)
int [] testArray = {4, 7, 4, 2, 7, 3, 7, 8, 3, 9, 1, 9};
int [ 3 maxVallndices;
int maxVal = Maxima(testArray, out maxVallndices);
Console.WriteLine("Maximum value {0} found at element indices: *.',
: ,;,. .;•'.;.•.• .;• ''. ;:, .,; •••;• •-.•:-- . m a x V a l ) ; :'':-: •.,':. ' ^ - 4 r . : 4 , '•[•, ' ' ••'
foreach (int index in maxVallndices)
Console.WriteLine(index);
Отладка и обработка ошибок 137
static int Maxima(int[] integers, out int[] indices)
Debug.WriteLine("Maximum value search started.");
indices = new int[l];
int maxVal = integers [0] ;
indices[0] = 0;
int count = 1;
•Debug--WriteLine {••"Maximum value initialized to " +
maxVal + ", at element index-0. ") ;
for (int i = 1; i < integers.Length; i++)
Debug.WriteLine(•Now looking at element at index
if (integers[i]> maxVal)
i + * . " ) ;
maxVal = integers[i] ;
count = 1;
indices = new int[l] ;
indices[0] = i;
Debug,WriteLine ("New maximum found. New value is "+ maxVal +
*, at element index " + i + * . * ) ; '
,:}. ..:..:;.:•.. :,.:•-. :,V:: Щ щ .. . щ - щ , | • | :• . . ^ '
else
{ •
if (integers[i] =- maxVal)
{ ' ' ;•,.•.•• ; ';
•• count++; :'-y'\• \.ry'-' • '•• .• :. .
int[] oldlndices = indices;
indices = new int{count];
oldlndices. CopyTo( indices , 0 1 ; ••
indices [count - 1] = i; :
Debug.WriteLine ("Duplicate maximum found at element index.* +
i + * . ") ;
; ; : У
Trace. WriteLine ("Maximum value " + maxVal + "found/ with • + count +
" occurrences.");
Debug.WriteLine("Maximum value search completed.");
return maxVal;
3. Запустите программу
в отладочном режиме
(см. рис. справа).
4. Завершите приложение
и посмотрите содержимое
окна Output (в режиме
Debug):
pfST
Haxi
9 li
Pi»es
ILiL
8ei|CSharp\C
mum yalue 9
to
ter7\ChCl7tH
found a t
coot in tie
element indices:
j
.-лт
• i
'DefaultDomain': Loaded 'c:\winnt\microsoft.net\frannework\v1.0.2901\mscorlib.dir,
No symbols loaded.
'ChO7ExO1': Loaded 'C:\BegCSharp\Chapter7\ChO7ExO1\bin\Debug\ChO7ExO1.exe',
Symbols loaded.
'ChO7ExO1.exe': Loaded
'c:\winnt\assembly\gac\system\1.0.2411.0_b77a5c561934eO89\system.dll',
No symbols loaded.
'ChO7ExO1.exe': Loaded
'c:\winnt\assembly\gac\system.xml\1.0.2411.0 Ь77а5с561934eO89\system.xml.dH',
No symbols loaded.
138 , Глава 7
Maximum value search started.
Maximum value initialized to 4, at element index 0.
Now looking at element at index 1.
New maximum found. New value is 7, at element index 1.
Now looking at element at index 2.
Now looking at element at index 3.
Now looking at element at index 4.
Duplicate maximum found at element index 4.
Now looking at element at index 5.
Now looking at element at index 6.
Duplicate maximum found at element index 6.
Now looking at element at index 7.
New maximum found. New value is 8, at element index 7.
Now looking at element at index 8.
Now looking at element at index 9.
New maximum found. New value is 9, at element index 9.
Now looking at element at index 10.
Now looking at element at index 11.
Duplicate maximum found at element index 11.
Maximum value 9 found, with 2 occurrences.
Maximum value search completed.
The program '[2056] ChO7ExO1.exe' has exited with code 0 (0x0).
Debug fc[ |
Debuq
5. Перейдите в режим Release, воспользовавшись
раскрывающимся меню панели инструментов
Standard (стандартные) (см. рис. справа).
6. Повторно запустите программу, на этот раз [.Configuration Manager,,,
в режиме Release (окончательный вариант),
и снова после завершения выполнения
приложения посмотрите окно Output:
'DefaultDomain': Loaded 'c:\winnt\microsoft.net\framework\v1.0.2901\mscorlib.dll',
No symbols loaded.
'ChO7ExO1': Loaded 'C:\BegCSharp\Chapter7\ChO7ExO1\bin\Release\ChO7ExO1 .exe\
No symbols loaded.
'ChO7ExO1.exe': Loaded
'c:\winnt\assembly\gac\system\1.0.2411.0 Ь77а5с561934eO89\system.dll', No
symbols loaded.
'ChO7ExO1.exe': Loaded
'c:\winnt\assembly\gac\system.xml\1.0.2411.0 b77a5c561934e089\system.xml.dll',
No symbols loaded.
Maximum value 9 found, with 2 occurrences.
The program '[1792] ChO7ExO1.exe' has exited with code 0 (0x0).
Как это работает
Это приложение является расширенной версией приложения, которое было ис-
пользовано в предыдущей главе. В нем применяется функция для вычисления мак-
симального значения, содержащегося в целом массиве. Этот вариант программы
возвращает также массив, содержащий индексы элементов, значение которых-
равно максимальному, что позволяет вызывающему коду выполнять над этими
элементами какие-либо действия. Давайте пройдем по этой программе.
Для начала обратите внимание, что в начале программы появился еще один
оператор using:
using System.Diagnostics;
Отладка и обработка ошибок 139
Он позволяет упростить доступ к функциям, которые обсуждались перед этим при-
мером, ПОСКОЛЬКУ ВСе ОНИ содержатся В Пространстве имен System.Diagnostics.
Без этого оператора все строки кода вроде:
Debug.WriteLine(*Bananas");
пришлось бы дополнительно квалифицировать, т. е. записывать в виде:
System.Diagnostics.Debug.WriteLine("Bananas");
Оператор using упрощает программу и делает ее менее многословной.
Код, находящийся в функции Main (), просто инициализирует тестовый массив
целых значений с именем testArray, а также объявляет еще один целый массив
с именем maxvaiindices, в котором будут храниться индексы, полученные от функ-
ции Maxima о (эта функция выполняет основные вычисления); затем код вызывает
эту функцию и после окончания ее работы выводит полученные результаты.
Функция Maxima () является несколько более сложной, но в ней нет почти ничего
такого, с чем вы еще не встречались. Поиск по массиву выполняется аналогичным
способом, как и функция Maxvaio из предыдущей главы, за исключением того,
что здесь ведется запись индексов элементов, обладающих максимальными зна-
чениями.
Возможно, ключевым кодом, на который следует обратить особое внимание
(кроме строк, отвечающих за вывод отладочной информации), является метод, ис-
пользуемый для отслеживания индексов. Вместо того чтобы возвращать массив,
который хранил бы все индексы (и, следовательно, был бы равен по размеру ис-
ходному массиву), функция Maxima о возвращает массив, чей размер соответствует
количеству индексов, которое должно в нем храниться. Это достигается путем по-
следовательного создания новых массивов по ходу поиска. Такой способ является
необходимым, поскольку размеры уже созданного массива не могут изменяться.
В самом начале поиска делается предположение, что именно первый элемент
исходного массива (для него используется локальное имя integers) имеет макси-
мальное значение и что он единственный элемент. Следовательно, можно при-
своить соответствующие значения переменной maxval (она возвращает значение
функции, равное найденному максимальному значению) и выходному массиву
indices, в котором сохраняются индексы элементов с максимальным значением.
Переменной maxval присваивается значение первого элемента массива integers,
а в indices заносится единственное значение — 0, которое является индексом
первого элемента массива. Мы также сохраняем число обнаруженных максималь-
ных значений в переменной с именем count, что позволяет отслеживать массив
indices.
Основным телом функции является цикл, который проходит по всем значениям
в массиве integers, за исключением самого первого, поскольку оно уже обработа-
но. Очередное значение сравнивается с текущим значением переменной maxval
и игнорируется, если maxval больше. Если проверяемое значение больше, чем
maxval, то в maxval и indices вносятся соответствующие изменения. Если значе-
ние оказывается равным maxval, то переменная count увеличивается на единицу,
а для хранения индексов создается новый массив indices. Этот новый массив име-
ет размерность на единицу больше, чем предыдущий, и в него записывается новый
обнаруженный индекс.
140 Глава 7
Код, реализующий последнюю функциональную возможность, имеет вид:
if (integers [i] == maxVal)
{
count++;
int[] oldlndices = indices;
indices = new int[count];
oldlndices.CopyTo(indices, 0);
indices [count - 1] = i;
Debug.WriteLine("Duplicate maximum found at element index • +
i + '.')}
>
Здесь происходит дублирование старого массива индексов в oldlndices, который
представляет собой целый массив, локальный для блока кода if. Обратите также
внимание на то, что значения, хранящиеся в массиве oldlndices, копируются
в новый массив indices с помощью функции <имямассива>.соруто о. Эта функция
получает в качестве параметров массив, в который осуществляется копирование,
и индекс первого копируемого элемента, после чего переносит в этот массив все
остальные значения.
С ПОМОЩЬЮ функций Debug.WriteLineO И Trace.WriteLine () на всем прОТЯЖе-
нии программы выводятся различные текстовые сообщения. Таким способом в от-
ладочном режиме мы получаем полный перечень выполняемых в цикле шагов,
которые и приводят к результату. В рабочем режиме мы наблюдаем только итог
вычислений, поскольку в этом режиме функция Debug.WriteLineO не работает.
Кроме рассмотренных функций с окончанием на writeLineO существует не-
сколько других функций, о которых также следует знать. Для начала упомянем
функции, ЯВЛЯЮЩИеСЯ Эквивалентами функции Console.Write () :
• Debug.Write()
• Trace.Write()
Обе ЭТИ фуНКЦИИ ИСПОЛЬЗуЮТ ТОТ Ж е СИНТакСИС, ЧТО И фуНКЦИИ WriteLineO (ОДИН
или два параметра, первый — с текстом сообщения и второй — необязатель-
ный — с категорией), но при этом они не добавляют символы "конец строки".
Существуют и другие команды:
• Debug.WriteLinelf()
• Trace.WriteLinelf()
• Debug.Writelf()
• Trace.Writelf()
Каждая из этих функций имеет те же параметры, что и аналогичные функции
"без if, с добавлением еще одного обязательного параметра, стоящего первым
в списке параметров. В качестве этого параметра используется логическое значе-
ние (или выражение, в результате вычисления которого получается логическое
значение), поэтому текст выводится только в том случае, если это значение true.
Эти функции применяются для вывода текста в окно Output при выполнении неко-
торых условий. Например, мы можем наложить требование выводить отладочную
информацию только в определенных ситуациях, т. е. в нашем коде может содер-
жаться огромное количество обращений к функции Debug.WriteLinelf о , при этом
выполнение каждой из них будет зависеть от текущих условий. Если соответствую-
щее условие не выполняется, то вывода производиться не будет, соответственно,
и окно Output не будет засоряться лишней информацией.
Отладка и обработка ошибок 141
Отладка в режиме останова
Прочие способы отладки работают в режиме останова программы. Перейти
в него можно несколькими способами, и все они тем или иным путем приводят
к временной остановке выполнения программы. В данном разделе мы сначала по-
знакомимся с этими способами, а затем рассмотрим вопрос, чего можно добиться
переходом в такой режим.
Переход в режим останова
Простейшим способом перехода в режим останова
является нажатие кнопки паузы в VS в процессе вы-
полнения приложения. Эта кнопка располагается на
панели инструментов Debug, которую необходимо до-
бавить к тем панелям инструментов, которые появля-
ются в VS по умолчанию. Для этого следует щелкнуть
правой кнопкой мыши в области панели инструментов
и выбрать панель Debug (см. рис. справа).
Data Design
Database Diagram
Debug'
Debug Location
Design
w
Crapr
— Г"-,;;.;
Hex
с программой, которая не
выполняется в настоящий
момент. Доступная кнопка —
"старт" — идентична кнопке,
расположенной на стандарт-
ной панели инструментов.
После запуска приложения
панель инструментов прини-
мает вид, показанный на ри-
сунке справа.
н
Пауза С ton Pec
Появившаяся панель ин-
струментов имеет вид, пока-
занный на рисунке слева.
Первые четыре кнопки на
этой панели предназначены
для ручного управления оста-
новкой программы. Три из
них окрашены в серый цвет,
так как они не могут работать
Hex
Теперь те три кнопки, которые прежде были серого цвета, перешли в рабочее
состояние и позволяют:
• Временно прекратить выполнение приложения (сделать паузу)
и перейти в режим останова.
• Полностью прекратить выполнение приложения
(это приводит не к переходу в режим останова,
а к полному выходу из приложения).
• Заново запустить приложение.
Пауза, пожалуй, является наиболее простым способом перехода в режим оста-
нова, но она не дает возможности точно определить, в каком именно месте прило-
жение будет остановлено. Наиболее распространено использование естественных
остановок в работе приложения, например, когда приложение ожидает ввода
142 Глава 7
информации от пользователя. Существует также возможность временной оста-
новки приложения при выполнении какой-либо продолжительной операции или
длинного цикла, но в этом случае конкретная точка, в которой мы остановимся,,
окажется абсолютно случайной.
В общем случае гораздо полезнее использовать точки останова (breakpoints).
Точки останова
Точка останова — это некоторый маркер в исходном коде, который вызывает
автоматическое переключение в режим останова. Возможны следующие настройки:
• Переходить в режим останова немедленно
по достижении точки останова.
• Переходить в режим останова по достижении точки останова
в том случае, если логическое выражение имеет значение true.
Q Переходить в режим останова по достижении точки останова
заданное число раз.
• Переходить в режим останова по достижении точки останова
в том случае, если с момента предшествующего достижения этой точки
значение переменной было изменено.
Обратите внимание, что все перечисленное выше
оказывается возможным только в том случае, если
приложение строилось в отладочном режиме. Если
же откомпилировать приложение с построением
окончательного варианта, то все точки останова
будут проигнорированы.
Существует три способа включать в программу
точки останова. Для задания простых точек, кото-
рые приводят к остановке программы в момент их
достижения, достаточно просто щелкнуть левой
кнопкой мыши по серой области, расположенной
слева от строки кода, или нажать правую кнопку
мыши на самой строке и выбрать пункт меню Insert
Breakpoint (вставка точки останова), как показано
на рисунке справа.
Включение точки останова приведет к появлению красного кружка рядом с со-
ответствующей строкой кода и к выделению самой строки:
Cut
Paste
akpbmt
New Breakpoint...
T*° Cursor
Ш
is!
20;
stacic void KainСstring[]
int[] ay = (4, 7, 5, 2, 7, 3, 8, 3, 3, 1, 9>;
i nz [ ] mxVa 11 nd i с е s;
iftt itiuxVal - Kaxima(test.AriraV/ out гшхУа!Indices);
Console * ¥r i teL ine (пШ>: iraum value {0) found at e leiaent ind ice
foreach (int index in maxValIndices)
i • : . : . • ' • • : ' • . : . ' ' • • • : • . . ' • ' • • • : : ' . :• . :-': : ' : : > ' : ; ' ' ; . : " - • • • • . • • • : ' /
Console, ¥r i t eL ine С index)':
Мы можем также получить информацию обо всех точках останова в данном
файле в окне Breakpoints. Необходимо активизировать это окно, выбрав пункт
Отладка и обработка ошибок
143
[^Breakpoints
ЩЫем X • <$$ Щ_
Name
I B i ^ f f-l-r-1 If,

— — — —
[ I 3 Щ : C o l u m n s • ; i ^ f j
( o n :
! 9 c h a r a c t e r 5 j . ( n o c o n d i t i o n )
H i t C o u n t
b r e a k a l w a y s
9 X меню Debug | Windows | Breakpoints.
В результате в нижней части экрана
появится окно (на том же месте, что
и окна Task List и Output), показанное
на рисунке слева.
С помощью этого окна мы можем
деактивировать точку останова (сняв
флажок, расположенный слева от
. описания точки останова; деактивированные точки изображаются в виде пустого
красного кружка), убрать точку останова или изменить ее свойства.
Свойства, изображенные в данном окне — Condition (условие) и Hit Count
(счетчик повторений) - всего лишь часть имеющихся, однако они являются наи-
более полезными. Мы можем отредактировать их, щелкнув правой кнопкой мыши
по соответствующей точке останова (в программе или в данном окне) и выбрав
пункт меню Properties. Теперь мы получаем возможность использовать три заклад-
ки: Function (функция), File (файл) и Address (адрес) - для изменения местополо-
жения точки останова (закладка Address позволяет устанавливать контрольную
точку по абсолютному адресу в памяти; это сложная тема, которой мы в данный
момент касаться не будем).
Нажатие кнопки Condition приводит
к открытию диалогового окна, представ-
ленного на рисунке справа. В верхней
части окна прочтем предупреждение:
"Когда достигается точка останова, произ-
водится вычисление выражения, и оста-
нов сработает только в том случае, если
значение выражения true или если это
условие было изменено.", ниже следуют
три флажка: "Условие" (выставив этот
флажок, можно ввести вычисляемое вы-
ражение в расположенное под ним поле),
"имеет значение true", "было изменено".
Breakpoint Condition
W h e n t h e b r e a k p Q i n t . t a c a t o i s r e a c h e d , t h e e x p r e s s i o n i s e v a l u a t e d a n d t h e
b r e a k p o i n t < 5 h i t o n l y i f t h e e x p r e s s i o r t j ' , e i t h e r t r u e o r h a s c h a n g e d .
Condition
<"* ts true
<~ ha-; changed
OK
Breakpoint Hit Count
В этом окне можно задать произвольное логическое выражение, состоящее из
любых переменных, область действия которых охватывает данную точку останова.
На приведенном выше рисунке изображена точка останова, которая будет сраба-
тывать, только если при ее достижении значение переменной maxval больше 4.
Мы можем также проверить, изменялось ли выражение, и остановиться, если
это имело место (для вышеприведенного случая переход может быть осуществлен,
только если значение maxval изменилось с 2 на 6 с момента предыдущего дости-
жения точки останова).
Нажатие кнопки Hit Count приводит
к открытию диалогового окна, пока-
занного на рисунке слева.
В верхней части окна прочтем пре-
дупреждение: "Точка останова срабаты-
вает, когда она достигается и при этом
условие оказывается выполненным.
Счетчик повторений — это число сраба-
тываний этой точки.", ниже из раскры-
вающегося списка можно выбрать
условие: "Когда должна срабатывать
A breakpoint »5 hit *hen the breakpoint location is reached and the condition is
satisfied. The hit count is the number of times the breakpoint has been hit.
When ;:he breakpoint is hit:
Current hit count: 0
.•'OK Cancel Help
144 Глава 7
контрольная точка:". Под списком слева находится кнопка "Обнулить счетчик повто-
рений", справа — информационная строка: "Текущее значение счетчика повторений:".
В этом диалоговом окне мы можем задать количество раз достижения точки
останова, прежде чем произойдет переход в режим останова. Раскрывающийся
список предлагает следующие возможности: переходить в режим останова всегда;
переходить в режим останова, когда счетчик повто-
break when the hit count is equal to
break when the hit count is a multiple of
break when the hit count is greater than or equal to
рений равен; переходить в режим останова, когда
счетчик повторений кратен; переходить в режим
останова, когда счетчик повторений больше или
равен (см. рис. слева).
Выбранная возможность совместно со значением, введенным в расположенное
рядом со списком текстовое поле, и определяет поведение точки останова.
Счетчик повторений оказывается полезным для циклов с большим числом по-
вторений, когда может потребоваться прервать выполнение программы, скажем,
после первых 5000 проходов. Не имея такой возможности, мы бы настрадались,
останавливая и запуская программу 5000 раз!
Другие способы перехода в режим останова
Существуют два других способа перехода в режим останова. Один из них — это
принятие решения о переходе в такой режим при возникновении необрабатывае-
мой исключительной ситуации. Эта тема рассматривается ниже в данной главе.
Другой способ прервать выполнение кода — создание утверждения (assertion).
Утверждения — это инструкции, позволяющие прерывать выполнение про-
граммы с выводом определяемого пользователем сообщения. Утверждения часто
используются в процессе разработки приложения для проверки того, все ли идет
правильно. Например, мы можем наложить требование, чтобы некоторая перемен-
ная в некоторой точке нашего приложения имела значение, меньшее 10. В этом
случае мы можем воспользоваться утверждением для проверки выполнения требо-
вания и прерывания программы при его нарушении. При проверке можно исполь-
зовать опцию Abort (окончить), которая завершит выполнение приложения; опцию
Retry (повторить), которая приведет к останову; и опцию Ignore (игнорировать),
которая позволит приложению выполняться дальше в обычном режиме.
Так же, как и функции для вывода отладочной информации, с которыми вы по-
знакомились ранее, функция, позволяющая использовать утверждение, имеет две
разновидности:
• Debug.As s ert()
• Trace.Assert()
Отладочный вариант функции—Debug. Assert о —будет компилироваться
только при создании отладочной версии.
Эти функции имеют три параметра. Первый из них — логическое значение,
причем если оно равно false, то срабатывает утверждение. Второй и третий пара-
метры имеют строковое значение и записывают информацию как в появляющееся
окно диалога, так и в окно Output. Для приведенного выше примера потребуется
следующий вызов функции:
Debug. Assert (myVar < 10/ "Значение переменной myVar больше или равно 10. " ,
"Невыполнение утверждения в Main ().");
Утверждения часто оказываются полезными на ранних этапах использования
приложения пользователями. Мы можем распространить рабочую версию прило-
Отладка и обработка ошибок 145
жения с функциями Trace.Asserto, что позволит разработчику отслеживать кор-
ректность функционирования данного приложения. Если какое-либо утверждение
окажется невыполненным, пользователь сообщит об этом разработчикам, которые
таким образом получают возможность проанализировать проблему, несмотря на
то, что они остаются в неведении, каким образом произошел сбой.
Можно, например, привести краткое описание ошибки в первой строке и ин-
струкции, объясняющие, что необходимо предпринять, во второй строке:
Trace.Assert(myVar < 10, "Выход значения переменной за допустимые границы.",
"Пожалуйста, сообщите разработчику код ошибки KCW001.*) ;
Assertion Failed: Abort=Qutt, Rett y=0ebug, Igrtor
Variable out of bounds, / - ' '
Please contact vendor v*ith theerror code KCWQOi'.
;'at Class! •
Abort
В том случае, если это утверждение
окажется невыполненным, пользователь
увидит на экране сообщение: "Выход
значения переменной за допустимые
границы. Пожалуйста, сообщите разра-
ботчику код ошибки KCW001.", ниже:
"в Class1.Main(StringQ args)"
Если у пользователя инсталлирован
VS и он нажмет кнопку Retry для рабо-
чей версии, то он увидит не исходный код, а инструкции приложения на языке
ассемблера, которые он вряд ли сможет понять. Ниже приводится участок кода
на языке ассемблера для примера из предыдущего раздела:
Retry
00000196
00000197
00000198
00000199
0000019a
0000019c
0000019d
пор
pop
pop
pop
mov
!РШ:;|||
ret •
ebx
esi
edi
esp,ebp
ebp
4
В этом совсем не просто разобраться, и только те программисты, у которых
имеется опыт работы с языком ассемблера, могут на что-то рассчитывать. А это
значит, что наша программа будет скрыта от (большинства) любопытных глаз!
Следующие темы касаются возможностей, появляющихся при останове прило-
жения. Вообще говоря, мы будем переходить в режим останова для того, чтобы
обнаружить ошибку в программе (или убедиться в том, что все работает правиль-
но). При останове можно использовать самые разнообразные методы, каждый из
которых позволяет производить анализ кода и конкретного состояния приложения
в точке временного прекращения работы.
Мониторинг содержимого переменных
Мониторинг содержимого переменных представляет собой пример той помощи,
которую оказывает нам VS. Самый простой способ узнать значение, хранящееся
в переменной, это подвести указатель мыши к имени переменной в исходном коде,
находясь в режиме останова. В этом случае на экране появится вспомогательное
поле желтого цвета, в котором содержится информация об этой переменной,
включая ее текущее значение.
Мы можем выделять таким же образом целые выражения, чтобы получить ин-
формацию о результате их выполнения. Однако применение этого способа весьма
ограниченно, поскольку он не позволяет, например, просматривать содержимое
массивов.
146 Глава 7
Вы, вероятно, уже успели заметить, что когда мы запускаем приложения по-
средством VS, то внешнее представление различных окон меняется. Во время вы-
полнения программы по умолчанию происходит следующее:
• Исчезает окно Properties.
• К окну Solution Explorer добавляется вкладка Running Documents
(используемые документы), которая показывает использующиеся
в проекте документы, если таковые существуют.
• Размер окна Output изменяется, поскольку половину
нижней части экрана занимает новое окно.
Это новое окно оказывается очень полезным для целей отладки. Оно позволяет
отслеживать значения переменных в приложении, которое находится в режиме
останова. В нем имеются три вкладки, которые используются следующим образом:
О Autos отображает переменные, используемые
в текущем и предшествующем операторах.
• Locals отображает все действующие переменные.
• Watch А/ предлагает настраиваемый вывод
переменных и выражений, где N изменяется от 1 до 4.
Новый вид экрана представлен на следующем рисунке:
ч ч r*.
clna-x CIASSS.
j ••-:•
• lest О **i
| л:
•:>:||
|;»Jr.»cie.ViiteLio« I »&*»-<) r
дттт „, ^ _J
Все эти окна работают более-менее аналогичным образом, предоставляя раз-
личные дополнительные возможности в зависимости от их конкретного предназна-
чения. Общим для всех окон является наличие списка переменных, в котором
представлена информация об имени, значении и типе переменной. Более сложные
переменные, такие как массивы, могут просматриваться посредством дополнитель-
ного запроса, для чего используются символы развертывания/свертывания (+ и -)
Отладка и обработка ошибок 147
с левой стороны от каждого имени,
позволяющие представлять содержи-
мое переменных в виде дерева. На-
пример, на рисунке справа изображен
вид экрана, который был получен по-
средством включения точки останова
в код предыдущего примера непо-
средственно после вызова функции
MaximaO. Здесь для просмотра раз-
вернута одна из переменных типа
массива — maxVallndices.
В этом окне также имеется возможность редактировать содержимое перемен-
ных, что позволяет эффективно обходить все другие способы присваивания, кото-
рые могли встречаться в предшествующем коде. Для этого достаточно просто
ввести новое значение в столбце Value (значение) для той переменной, которую
мы хотим отредактировать. Этот способ может использоваться, к примеру, в тех
случаях, когда требуется проверить работу некоторых сценариев, для чего в про-
тивном случае пришлось бы вносить изменения в программу.
Окна Watch (просмотр), которых может быть не более 4, позволяют осуществ-
лять мониторинг определенных переменных или выражений, содержащих опреде-
ленные переменные. Для того чтобы воспользоваться этим окном, достаточно
просто набрать имя переменной или выражения в столбце Name (имя) и посмот-
реть на результат. Не следует забывать, что некоторые переменные в приложении
в данный момент могут находиться вне области своего действия и будут соответст-
вующим образом помечены в окне Watch.
На рисунке слева изображено окно про-
смотра с некоторыми переменными и вы-
ражениями, использованными в качестве
примера. В данном случае вновь исполь-
зован код из предыдущей программы, вы-
полнение которой остановлено на функции
Maxima().
Массив testArray является локальным по отношению к MainO, поэтому
в таком случае мы не можем увидеть его значений. Вместо этого мы получаем со-
общение о том, что данная переменная находится вне своей области действия.
Существует также возможность добавлять переменные в окно Watch, перенося
их мышью из исходного кода.
Воспользоваться остальными окнами можно с помощью пунктов меню Debug |
Windows | Watch | Watch N. В каждом окне может содержаться свой собственный
набор переменных и выражений, что позволяет группировать связанные между со-
бой переменные для удобства просмотра.
Помимо всех этих окон просмотра существует еще окно QuickWatch (быстрый
просмотр), которое позволяет оперативно получать информацию о переменных из
исходного кода. Для этого след
Категория: информатика | Просмотров: 1296 | Добавил: basic | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Календарь
«  Февраль 2010  »
ПнВтСрЧтПтСбВс
1234567
891011121314
15161718192021
22232425262728
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

krutoto.ucoz.ru
Бесплатный конструктор сайтов - uCoz