Итак, вы хотите заглушить это предупреждение в Visual C++…Источник: habrahabr Дмитрий Мещеряков
Итак, вы хотите заглушить это предупреждение в Visual C++…Обычная ситуация: вы написали кусок безупречно правильного кода, но Visual C++ выдает на нем предупреждение. Часто можно немного переписать код, чтобы предупреждение ушло, но не всегда, и тогда выход один - глушить выдачу этого предупреждения.
Рассмотрим, какие возможности для этого есть в Visual C++ и какие ошибки допускают при их использовании. Самая очевидная первая возможность - запретить предупреждение в настройках проекта на уровне проекта . Это работает, но плохо. Во-первых, предупреждение будет заглушено во всем проекте, в том числе и во всех заголовках, которые этот проект включает в себя. Во-вторых, если вы скопируете код в другой проект, предупреждение появится снова. Это неизбежно произойдет в случае кода в заголовочных файлах (например, содержащими реализацию шаблонов), который необходимо включать (#include) в каждый проект, который их использует. Следующая возможность - запретить предупреждение в настройках проекта на уровне файла . Этот способ еще хуже предыдущего. Во-первых, предупреждение будет заглушено на всю единицу трансляции, т.е. в этом файле и всех заголовках, которые он включает. Во-вторых, точно те же проблемы с копированием кода, что и в прошлый раз. В третьих, как только в проекте оказывается больше нескольких файлов, вероятность потерять эту настройку при конверсии проекта под более новую версию Visual C++ становится равной чуть менее, чем единице. Остается использование #pragma warning. Обычно ее используют так:
… и остаются очень довольны собой. Предупреждение заглушили, код написали, предупреждение восстановили. Прибыль. На самом деле, это FAIL. Пора внимательно прочитать (да, внимательно и да, прочитать, а не копипастить код откуда попало) описание #pragma warning (default). Там говорится следующее: эта конструкция 1. устанавливает предупреждению уровень по умолчанию и Сначала уровни. В Visual C++ с каждым предупреждением связано число от 1 до 4 - это уровень предупреждения. Предупреждения уровня 1 считаются более серьезными, с ростом уровня серьезность якобы снижается. У каждого предупреждения есть уровень по умолчанию. Конструкция
устанавливает предупреждению указанный в ней уровень и включает предупреждение, т.е. уровень не прибит гвоздями, его можно поменять. У компилятора есть настройка, с какого уровня предупреждения показывать, 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), которая включает предупреждение. Что особенно приятно, эти ситуации возникают в самый подходящий момент - при переходе с одной версии компилятора на другую, при попытке включить в проект кучу стороннего кода, который и без того не прост в использовании, вторая ситуация просто приводит к подавлению предупреждения, в результате можно пропустить ошибку в коде, которая позже поможет пользователям получить премию Дарвина. На самом деле, предупреждения нужно глушить так:
Первая конструкция сохраняет текущее состояние настроек предупреждений, вторая отключает нужное предупреждение, третья - восстанавливает сохраненное состояние. При этом состояние восстанавливается полностью - все сделанные уровнями выше изменения тоже восстанавливаются, предупреждения, выключенные по умолчанию, не включаются. Выглядит страшно, но чего не сделаешь, чтобы не пропустить ту самую ошибку на миллиард. Дмитрий Мещеряков |