Отладка приложений

       

Рассматривайте предупреждения как возможные ошибки


Поскольку Visual Basic намного более чувствителен к ошибкам компиляции, чем C++, то все, что компилятор сообщает вам, является ошибками. Как знает каждый, кто компилировал какую-нибудь программу, более сложную чем "Hello, World!", C++ — значительно более свободный язык, который позволяет избежать многих неприятностей. Подобно Visual Basic, Visual C++ имеет некоторые трудные ошибки, аварийно завершающие компиляцию. Такие ошибки, как С2037 ("left of 'operator' specifies undefined struct/union 'identifier1— "слева от 'операция' указан неопределенный 'идентификатор' struct/union"), означают, что компилятор не может продолжать выполнение. Visual C++ отличается от Visual Basic в первую очередь тем, что первый может (кроме ошибок) выдавать также предупреждения.

Эти предупреждения, в общем случае, означают, что некоторая часть кода неоднозначна, но компилятор сделает обоснованное предположение о правильном значении. Превосходным примером является предупреждение типа С4244 ("'conversion' conversion from 'typel' to 'type2', possible loss of data" — '"преобразование1преобразование из 'тип Г в 'тип2', возможная потеря данных"), которое всегда выводится при преобразованиях типов со знаком и без знака. Многие думают, что предупреждения являются только предупреждениями, но я считаю, что любое предупреждение — это то же самое, что ошибка, и что нужно трактовать его как ошибку— увидев предупреждение компилятора, следует остановиться и исправить текст программы, сделав его однозначным для компилятора.

Те, кто изучал конструкцию компилятора, в частности синтаксический анализатор, вероятно, знают, что синтаксический анализ очень труден, особенно в столь сложном языке, как C++. Компилятор Visual C++ выдает предупреждения, сообщая, что код является неоднозначным, и пытается предположить, что программист имеет в виду. Позволять инструменту делать предположения за человека — это верный способ ввести ошибки. Борясь с ошибкой, необходимо прежде всего убедиться, что код компилируется без предупреждений.


Проекты по умолчанию, создаваемые мастерами Visual C++, выдают предупреждения 3-го уровня, которые соответствуют ключу /из компилятора CL.EXE. Следующий уровень предупреждений — 4 (ключ /W4), и можно даже заставить компилятор трактовать все предупреждения как ошибки (ключ /их). Все эти уровни легко установить в диалоговом окне Project Settings интегрированной среды разработки (Integrated Development Environment — IDE) Visual C++. Уровень предупреждений устанавливается в комбинированном поле Warning Level на вкладке C/C++, General Category, а ключ /wx — с помощью флажка Warnings As Errors, расположенного ниже поля Warning Level.

Можно почти доказать утверждение: "Все проектные конструкции должны компилироваться с предупреждениями уровня 4, и все предупреждения следует трактовать как ошибки", но действительность заставляет смягчить это требование. Во-первых, некоторые общие файлы заголовков не будут компилироваться с ключами /wх и /w4. Сам компилятор имеет пару ненужных информационных предупреждений, которые он трактует как реальные предупреждения, поэтому ключ /wх остановит компиляцию. Стандартная библиотека шаблонов (Standard Template Library — STL), поставляемая вместе с Visual C++, генерирует много предупреждений 4-го уровня. Некоторые проблемы порождает также применение шаблонов с компилятором. К счастью, программист может работать, не думая о большинстве этих проблем и предупреждений.

Можно предположить, что стоит только установить предупреждения уровня 4 и выключить рассмотрение предупреждений как ошибок, как все будет прекрасно, однако в действительности эта схема не достигает цели. Оказывается, разработчики быстро теряют чувствительность к предупреждениям в окне Build1. Если не исправлять все предупреждения, то, независимо от того, насколько безобидными они оказываются, более важные предупреждения пропускаются, потому что они скрыты в потоке вывода. Для того чтобы сделать возможной обработку лишь некоторых предупреждений, следует применить более тонкий подход.


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

#pragma warning, которая, кроме того, позволяет управлять уровнем ошибок вокруг определенных заголовков.

Хороший пример понижения уровня ошибок — включение файлов заголовков, которые не компилируются с предупреждениями 4-го уровня. Расширенная директива #pragma warning, первоначально предложенная в Visual C++ 6, может понизить уровень предупреждений. В следующем отрывке кода устанавливается уровень предупреждений перед включением подозрительного файла заголовков и повторно устанавливается так, чтобы код компилировался с предупреждениями уровня 4:

#pragma warning ( push, 3)

#include "IDoNotCompileAtWarning4.h"

#pragma warning ( pop)

С помощью директивы #pragma warning также можно выключать индивидуальные предупреждения. Эта директива оказывается полезной, если при использовании неименованной структуры или объединения получена ошибка С4201 ("nonstandard extension used: nameless struct/union" — "использовано нестандартное расширение: неименованная структура/объединение") с предупреждениями уровня 4. Чтобы выключить эти предупреждения, используется директива #pragma warning, как показано в следующем коде. Заметьте, что в нем прокомментировано выключение предупреждения и приведено соответствующее предупреждение. Выключая индивидуальные предупреждения, убедитесь, что ограничили область действия директивы #pragma warning определенной секцией кода. Если разместить директиву слишком высоко, то можно замаскировать другие проблемы в программе.

// Выключить предупреждение

// "nonstandard extension used: nameless struct/union"

// потому что я не пишу переносимый код

tpragma warning ( disable : 4201)

struct S

{

float y;

struct

 Это окно открывает команда Build из меню Build интегрированной среды разработки. — Пер.

{

int a;

int b;

int c;

};.

} *p_s;



// Включить предупреждение обратно.

 #pragma warning ( default : 4201)

Если STL не используется, то данная схема работает хорошо, а если да, то она может работать, а может и не работать. Прежде чем понижать уровень ошибок с помощью директивы #pragma warning ( push, 3), обязательно пытайтесь получить STL-заголовки, чтобы компилировать на 4-ом уровне предупреждений. При этом, может быть, придется выключить некоторые дополнительные индивидуальные предупреждения, но надо стремиться сохранять 4-й уровень предупреждений, если это возможно. Для пары проектов я так и не получил компилированного кода без предупреждений, как бы ни "вылизывал" программу. В этих случаях я понизил глобальный уровень предупреждений до 3. Даже тогда, однако, я сохранил включенным режим "Warnings As Errors" (ключ /wx).

Суть в том, что следует пытаться компилировать с самым высоким возможным уровнем предупреждений и трактовать все предупреждения как ошибки , с самого начала работы над проектом. Впервые повысив уровень предупреждений проекта, вы, вероятно, будете удивлены количеством полученных предупреждений. Просмотрите код и исправьте каждое из них. Вероятно, простое исправление предупреждений устранит ошибку или две. Для тех, кто думает, что компиляция программы с ключами /W4 и /wx невозможна, есть иное доказательство: весь код примеров на сопровождающем эту книгу компакт-диске скомпилирован с установкой обоих флагов для всех конфигураций.



Содержание раздела