Pull to refresh
0
Content AI
Решения для интеллектуальной обработки информации

Итак, вы хотите заглушить это предупреждение в Visual C++…

Reading time 4 min
Views 33K
FAILОбычная ситуация: вы написали кусок безупречно правильного кода, но Visual C++ выдает на нем предупреждение. Часто можно немного переписать код, чтобы предупреждение ушло, но не всегда, и тогда выход один – глушить выдачу этого предупреждения.

Рассмотрим, какие возможности для этого есть в Visual C++ и какие ошибки допускают при их использовании.



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

Следующая возможность – запретить предупреждение в настройках проекта на уровне файла. Этот способ еще хуже предыдущего. Во-первых, предупреждение будет заглушено на всю единицу трансляции, т.е. в этом файле и всех заголовках, которые он включает. Во-вторых, точно те же проблемы с копированием кода, что и в прошлый раз. В третьих, как только в проекте оказывается больше нескольких файлов, вероятность потерять эту настройку при конверсии проекта под более новую версию Visual C++ становится равной чуть менее, чем единице.

Остается использование #pragma warning. Обычно ее используют так:

#pragma warning (disable: 9000)
// код, провоцирующий предупреждение C9000
#pragma warning (default: 9000)

… и остаются очень довольны собой. Предупреждение заглушили, код написали, предупреждение восстановили. Прибыль.

На самом деле, это FAIL. Пора внимательно прочитать (да, внимательно и да, прочитать, а не копипастить код откуда попало) описание #pragma warning (default). Там говорится следующее: эта конструкция

1. устанавливает предупреждению уровень по умолчанию и
2. включает предупреждение.

Сначала уровни. В Visual C++ с каждым предупреждением связано число от 1 до 4 – это уровень предупреждения. Предупреждения уровня 1 считаются более серьезными, с ростом уровня серьезность якобы снижается. У каждого предупреждения есть уровень по умолчанию. Конструкция

#pragma warning(Level: Warning)

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

У компилятора есть настройка, с какого уровня предупреждения показывать, Warning Level. При значении этой настройки, равном A, предупреждение в конкретной строке кода показывается только в том случае, если оно там разрешено и его уровень составляет A или ниже.

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

Рассмотрим, как проявляется FAIL при использовании #pragma warning (default).

FAIL 1. Предупреждение C9001 выключено по умолчанию. Код в заголовочном файле использует #pragma warning(default:9001), чтобы «восстановить» предупреждение, заглушенное в небольшом куске кода.

Зачем он это делает, если предупреждение и так выключено? Список предупреждений, выключенных по умолчанию, меняется от одной версии Visual C++ к другой – в него понемногу добавляются предупреждения. Если код изначально писали для Visual C++ 7, а там C9001 по умолчанию было включено, а теперь компилируют в Visual C++ 10, и в нем предупреждение уже выключено, то такая конструкция смысла не имеет, а могла просто достаться в наследство.

В результате #pragma warning(default) принудительно включает предупреждение, выключенное по умолчанию.

FAIL 2. У предупреждения C9002 уровень по умолчанию 3, а проект компилируется с уровнем 2, т.е. «показывать предупреждения уровня 2 и ниже». После долгих раздумий разработчики решили, что на самом деле предупреждение C9002 достаточно серьезное, чтобы удостоить его уровня 2, т.е. принудительно повысить серьезность. Соответственно, каждый проект включает в себя стандартный заголовок, попадающий затем во все единицы трансляции, который содержит конструкцию #pragma warning(2:9002).

Чуть ниже по тексту в единице трансляции оказывается #pragma warning(default:9002), которая сбрасывает уровень обратно на 3, и при компиляции с уровнем 2 предупреждение не выдается. Кстати, это предупреждение сообщало о серьезном дефекте. Улыбаемся и машем. В обратную сторону тоже работает — предупреждению «повысили» уровень с 2 до 3, чтобы оно не выдавалось в проектах, компилируемых с уровнями 2 и ниже (т.е. понизили серьезность), но #pragma warning(default) сбрасывает уровень на 2, и предупреждение выдается.

FAIL 3. Предупреждение C9003 по умолчанию включено, но продумано так плохо, что никто не может припомнить, когда оно выдается по делу. Разработчики решаются заглушить его повсюду, использовав #pragma warning(disable:9003) в общем заголовочном файле. Ниже по единице трансляции оказывается #pragma warning(default:9003), которая включает предупреждение.

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

На самом деле, предупреждения нужно глушить так:

#pragma warning(push)
// хорошие, годные вакансии: www.abbyy.ru/vacancy
#pragma warning(disable:9000)
// код с предупреждением C9000
#pragma warning(pop)

Первая конструкция сохраняет текущее состояние настроек предупреждений, вторая отключает нужное предупреждение, третья – восстанавливает сохраненное состояние. При этом состояние восстанавливается полностью – все сделанные уровнями выше изменения тоже восстанавливаются, предупреждения, выключенные по умолчанию, не включаются.

Выглядит страшно, но чего не сделаешь, чтобы не пропустить ту самую ошибку на миллиард.

Дмитрий Мещеряков,

департамент продуктов для разработчиков
Tags:
Hubs:
+20
Comments 27
Comments Comments 27

Articles

Information

Website
www.contentai.ru
Registered
Founded
Employees
101–200 employees
Location
Россия