О пользе Warning Level /W4
Современный компилятор Microsoft С/C++ способен предупреждать о большом количестве потенциальных проблем в исходном коде, что часто бывает слишком назойливо при компиляции миллионов строк старого кода. Поэтому по умолчанию используется уровень предупреждений /W3.
С другой стороны, это просто неразумно не использовать такую помощь со стороны компилятора, если мы создаем новый код на C++ и не слишком скованы вопросами обратной совместимости (backward compatibility). И все же уровень предупреждений /W4 в "чистом виде" порождает слишком много предупреждений, которые хочется видеть только "когда спросишь". Иначе за большим потоком "назойливых" предупреждений легко проглядеть важное.
Поэтому стандартная конфигурация во всех проектах, над которыми я работал и работаю такова:
- Warning level /W4 обязателен;
- Флаг /WX делает отсутствие предупреждений обязательным условием успешной компиляции;
- Используется выработанный годами список предупреждений, которые полезно отключить, чтобы сделать уровень /W4 "разумно строгим":
#if !defined( _ALL_WARNINGS )
#pragma warning(disable: 4061) // not all enum values present in switch statement
#pragma warning(disable: 4068) // unknown pragma
#pragma warning(disable: 4127) // constant expression
#pragma warning(disable: 4201) // nameless structs are used
#pragma warning(disable: 4214) // nonint packed fields are used
#pragma warning(disable: 4275) // nonexport class is a base for export one
#pragma warning(disable: 4310) // cast truncates constant value
#pragma warning(disable: 4511) // copy constructor could not be generated
#pragma warning(disable: 4512) // assignment operator could not be generated
#pragma warning(disable: 4705) // statement has no effect in optimized code
#pragma warning(disable: 4725) // FDIV Pentium(r) known issue
#if defined( _DEBUG )
#pragma warning(disable: 4706) // assignment within conditional expression
#else
#pragma warning(disable: 4702) // unreachable code caused by optimizations
#pragma warning(disable: 4791) // loss of debugging info in retail version
#endif
#if !defined( _SHOW_INLINE )
#pragma warning(disable: 4505) // unreferenced static function removed
#pragma warning(disable: 4514) // unreferenced inline function removed
#pragma warning(disable: 4710) // inline function not expanded
#endif
#if !defined( _SHOW_DEPRECATED )
#pragma warning(disable: 4996) // 'function' was declared deprecated
#endif
#endif
Важно:
- Все #pragma warning(disable) должны быть сосредоточены в одном, хорошо известном месте. Это помогает четко отслеживать конфигурацию проекта, например при такой обязательной процедуре как инспекция кода (code inspection). Поэтому приведенный выше фрагмент полезно включить в header file самого низкого уровня иерархии, что-нибудь типа BaseAPI.h или Common.h. Тогда все единицы компиляции *.cpp будут обрабатываться одинаково.
- Обязательно должна быть возможность временного включения всех предупреждений, и это полезно делать периодически. По крайней мере, совершенно необходимо при переходе на новую версию компилятора, чтобы убедиться: да, отключение этих предупреждений по-прежнему имеет смысл.
- Чем более предсказуемы имена управляющих символов, тем лучше. Например, я использую _ALL_WARNINGS, а не какой-нибудь SHOW_DISABLED_WARNINGS по одной простой причине: глобальный поиск по дереву проекта покажет также и _AFX_ALL_WARNINGS, и _ATL_ALL_WARNINGS. А если все управляющие символы условной компиляции явно перечислены в каком-нибудь ReadMeFirst.txt из корневого каталога проекта, тогда уж вообще хорошо.