Сегодня рассмотрим некоторые приёмы работы с отладчиком и поучимся исправлять ошибки.

Приступим. Для сегодняшнего выпуска я создал новое решение solution. Оно включает в себя два проекта: hello_world и debugger (отладчик). В hello_world содержится код программы из первых выпусков, а вот с проектом debugger мы и будем работать.

В проект был добавлен один файл debugger.cc, который содержит следующий код:

код на языке c++
#include <conio.h>
#include <iostream>
#include <clocale>

using namespace std;

int main ()
{
  setlocale(LC_CTYPE,"Russian");

  char var = 'я';
  cout << var;

  _getch();
  return 0;
}

Стартовым проектом по умолчанию выбран debugger.

В программе переменной var присваивается символ, а затем эта переменная выводится на экран.

Выбираем пункт меню Build → Build solution (Построение → Построить решение) или нажимаем F7. Смотрим на окно Output (Вывод) внизу экрана.

1>------ Build started: Project: hello_world, Configuration: Debug Win32 ------
2>------ Build started: Project: debugger, Configuration: Debug Win32 ------
1>Compiling...
2>Compiling...
2>debugger.cc
1>hello_world.cc
1>Compiling manifest to resources...
2>Compiling manifest to resources...
2>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation. All rights reserved.
2>Copyright (C) Microsoft Corporation. All rights reserved.
1>Linking...
2>Linking...
1>Embedding manifest...
2>Embedding manifest...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>Build log was saved at "file://d:\job\c\solution\hello_world\Debug\BuildLog.htm"
1>hello_world - 0 error(s), 0 warning(s)
2>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
2>Copyright (C) Microsoft Corporation. All rights reserved.
2>Build log was saved at "file://d:\job\c\solution\debugger\Debug\BuildLog.htm"
2>debugger - 0 error(s), 0 warning(s)
========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Здесь описан процесс сборки решения (building - сборка, построение). Сборка включает в себя компиляцию (compiling) и компоновку (linking). Кроме компиляции и сборки исходного кода в данном окне можно увидеть компиляцию и встраивание манифестных файлов (строки: Compiling manifest to resources... и Embedding manifest). На данный момент манифестные файлы нам не нужны. К концу данного текста встречаются две строки:

1>hello_world - 0 error(s), 0 warning(s)

2>debugger - 0 error(s), 0 warning(s)

Или:

1>hello_world - 0 ошибок, 0 предупреждений

2>debugger - 0 ошибок, 0 предупреждений

Эти строки говорят как была произведена сборка проектов. Если есть хоть одна ошибка, то собрать проект не получилось, соответственно его не получится и запустить. Если есть предупреждения, то проект запустить можно, но в коде что-то не так. Например, предупреждения выдаются когда переменные объявляются, но не используются.

И последняя строка относится к решению:

========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Первое число - сколько проектов успешно (succeeded) собрано, второе - сколько собрать не получилось (failed). В данном случае успешно собраны оба проекта.

Сейчас сделаем несколько ошибок.

Для начала уберём из следующей строки точку с запятой:

char var = 'я'

Пытаемся скомпилировать проект. В окне вывода можно обнаружить следующие строки:

1>debugger - 1 error(s), 0 warning(s)

========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========

Первая строка означает, что в проекте debugger одна ошибка, а вторая - что один проект скомпилировался успешно, а сборка ещё одного завершилась неудачей.

В панели иструментов окна Вывод (output) есть три кнопки: Find Message in Code (Найти сообщение в коде), Go to Previous Message (Перейти к предыдущему сообщений) и Go to Next message (Перейти к следущему сообщению).

Чтобы найти ошибку, нужно щёлкнуть по одной из кнопок: Перейти к предыдущему сообщению или Перейти к следующему сообщению. В окне Вывод выделится строка в которой содержится сообщение об ошибке:

2>d:\job\c\solution\debugger\debugger.cc(14) : error C2146:
syntax error : missing ';' before identifier 'cout'

Сообщение значит примерно следущее: В файле debugger.cc в четырнадцатой строке (число в скобках) допущена ошибка C2146 и дано её описание - ошибка в синтаксисе: отсутствует ';' перед идентификатором 'cout'.

Теперь нужно щёлкнуть на кнопку Найти сообщение в коде. В редакторе выделится строка, где по мнению компилятора была допущена ошибка. Думаю, понятно что нужно сделать - добавить ';'.

Ошибки показываются прямо в окне Output. Но есть ещё одно специальное средство. Если во вкладках под окном Вывод нет вкладки Error List (Список ошибок), то выберите пункт меню View -> Other windows -> Error List (Вид -> Другие окна -> Список ошибок).

Теперь исправляем ошибку с точкой запятой и делаем новую. В слове char убираем букву r. И снова собираем решение.

В этот раз в окне Вывод, в проекте debugger появилось сообщение сразу о четырёх ошибках:

2>debugger - 4 error(s), 0 warning(s)

Можно просмотреть эти ошибки в окне Вывод, а можно и в окне Список ошибок. Для этого нужно открыть вкладку Error List:

В данном окне можно по выбору просматривать ошибки, предупреждения и сообщения.
Итак, здесь мы видим четыре ошибки. В окне Список ошибок несколько полей: тип, представленный значком (ошибка, сообщение или предупреждение), номер, описание, файл, строка.

Ошибки нужно всегда исправлять с самой первой.
В описании первой ошибки мы видим:

'cha': undeclared identifier

То есть необъявленный идентификатор cha. В общем-то уже понятно в чём проблема. Щёлкаем два раза на эту строку и курсор в редакторе перейдёт на нужную строку. Осталось только добавить букву r.

В некоторых случаях при сборке программы компилятор может выдать десятки ошибок, при этом реальных ошибок окажется 2-3.

Это что касается ошибок во время компиляции. Тут всё относительно просто.

Существуют также ошибки времени выполнения программы, которые в свою очередь делятся на две группы: логические ошибки, при этом программа выполняется нормально, но результат неверен (в одном из уроков раздела DirectX у нас будет замечательное упражнение на эту тему). Например: неверные значения переменных. Вторая группа ошибок времени выполнения приводит к остановке программы. Причина таких ошибок - работа с низкоуровневыми возможностями языка: выделение памяти (указатели), работа с файлами. Это разграничение конечно же довольно условно.

Для обработки ошибок из второй группы существует механизм исключений. С исключениями мы познакомимся позже. Здесь же мы рассмотрим возможности отладчика, которые сделают вашу жизнь намного легче.

В программе debugger я объявил одну переменную глобальной:

int i = 1;

А в код main добавил следущее:

код на языке c++
float f1 = 1.5;
float f2 = 2.5;
float* ptr = &f2;

ptr = &f1;
cout << f1 << "\n";

Break points - точки прерывания (точки остановки)

Break points позволяют остановить выполнение программы в определённом месте. Для создания точки нужно всего-лишь щёлкнуть мышкой напротив нужной строки:

Собираем программу, жмём F5 или выбираем пункт меню Debug -> Start Debugging (Отладка -> Начать отладку).

На картинке показана уже запущенная программа с двумя точками прерывания. Во время отладки вместо окна Вывод появляются два новых.

В первом окне есть следующие вкладки: Autos (Автоматические данные), Locals (Локальные данные), Threads (Потоки), Modules (Модули), Watch 1 (Наблюдаемые данные 1).

Во втором окне: Call Stack (Стек вызовов), Breakpoints (Точки остановки), Output (Вывод).

Чтобы продолжить выполнение программы после точки прерывания нужно нажать F5. Чтобы закончить отладку - Shift+F5.

Чтобы добавить к интерфейсу отладки дополнительные окна, необходимо выбрать пункт меню Debug → Windows -> Необходимое окно (Отладка -> Окна -> Необходимое окно).

На данный момент нам интересны вкладки Locals (Локальные данные) и Watch 1.

На вкладке Locals видны все локальные переменные. Здесь можно узнать имя переменной, значение и тип.

Если переменных в программе слишком много, то часть из них можно добавить в наблюдаемые. Для этого во время отладки, в редакторе щёлкните на имя переменной правой кнопкой мыши и выберите пункт Add Watch (Добавить в наблюдаемые):

После этого, данные о переменной можно увидеть на вкладке Watch 1.

Обратите внимание, что нельзя поставить точку остановки в глобальной области видимости, только в функции main() и на уровнях ниже.

Ну и напоследок несколько слов об остальных вкладках:

* На вкладке Autos можно найти значения переменный, которые используются непосредсвенно рядом с текущей точкой остановки.
* На вкладке Threads (Потоки) перечислены все потоки программы. Очень долго мы будем работать с однопоточнымии приложениями, так что пока эта вкладка для нас не актуальна.
* Modules. Здесь перечислены модули (файлы) необходимые для запуска программы.
* Call stack (стек вызовов) позволяет посмотреть вызовы функций программы. Кстати, загляните в эту вкладку - узнаете как запускается программа.
* Output (вывод). На данной вкладке можно узнать в каком порядке загружаются модули необходимые для выполнения программы.

Вот в общем-то все средства необходимые для более-менее комфортного существования в страшном мире отлова ошибок. Конечно же не рассмотрены более продвинутые средства. Например, фильтры точек остановки, просмотр регистров или кода ассемблера. Но это, наверное, тема другого сайта.

На сегодня всё. В качестве упражнений позапускайте старые программы и проследите значения: объектов, указателей, массивов.