Часто, работая с C ниже gcc
, я начинаю со следующего набора предупреждающих флагов (с трудом собранных из нескольких источников):
-Wall -Wextra -Wformat-nonliteral -Wcast-align -Wpointer-arith -Wbad-function-cast \
-Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations -Winline -Wundef \
-Wnested-externs -Wcast-qual -Wshadow -Wwrite-strings -Wno-unused-parameter \
-Wfloat-equal -pedantic -ansi
Я буду собирать (по крайней мере, мои отладочные версии) с этим набором предупреждений и исправлять все, что я могу (обычно все), а затем снимать флаги только в том случае, если они либо не актуальны, либо не исправимы (почти никогда). Иногда я также добавляю, -Werror
если мне нужно отойти во время компиляции.
Я только начинаю изучать C ++ (да, я на 15 лет отстал от времени), и мне бы хотелось начать с правильного пути.
Мой вопрос: есть ли у кого-нибудь предварительно скомпилированный аналогичный набор полных предупреждений для C ++ g++
? (Я знаю, что многие из них будут такими же.)
-Wall
) является-Wbloody_everything
флаг :-)-Weverything
. Я читал, что даже разработчики Clang ++ немного обеспокоены тем, что пользователи его включают; очевидно, он был предназначен только для внутреннего использования. Однако это не имеет смысла, потому что включение,-Weverything
вероятно, лучший способ обнаружить потенциально полезные предупреждения, о которых вы раньше не знали.Ответы:
Я просмотрел и нашел минимальный набор включений, который должен получать максимальный уровень предупреждений. Затем я удалил из этого списка набор предупреждений, которые, как мне кажется, на самом деле не указывают на то, что происходит что-то плохое, или имеют слишком много ложных срабатываний для использования в реальной сборке. Я прокомментировал, почему все исключенные мной были исключены. Это мой последний набор рекомендуемых предупреждений:
-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused
Имеются сомнительные предупреждения:
Я включаю,
-Wno-unused
потому что у меня часто есть переменные, которые я знаю, что буду использовать позже, но для которых еще нет написанных функций. Удаление предупреждений об этом позволяет мне писать в своем предпочтительном стиле, иногда откладывая реализацию вещей. Полезно выключать это время от времени, чтобы убедиться, что ничего не проскочило через щели.-Wdisabled-optimization
похоже на сильную настройку предпочтений пользователя. Я только что добавил это в свою сборку (только для оптимизированных сборок по понятным причинам), и ничего не получилось, так что это не кажется особо разговорчивым предупреждением, по крайней мере, для того, как я кодирую. Я включаю его (хотя код, который вызывает это предупреждение, не обязательно ошибочен), потому что я верю, что могу работать с моими инструментами, а не против них. Если gcc сообщает мне, что он не может оптимизировать код в соответствии с тем, как я его написал, то мне следует подумать о его переписывании. Я подозреваю, что код, который запускает это предупреждение, в любом случае может выиграть от большей модульности, поэтому, хотя код не является технически неправильным (вероятно), стилистически скорее всего так.-Wfloat-equal
предупреждает о безопасном сравнении равенства (в частности, сравнение с невычисленным значением -1). Пример в моем коде, где я использую это, заключается в том, что у меня есть вектор с плавающей запятой. Я просматриваю этот вектор, и есть некоторые элементы, которые я пока не могу оценить, какими они должны быть, поэтому я установил для них -1.0f (поскольку моя проблема использует только положительные числа, -1 находится вне области). Позже я просматриваю и обновляю значения -1.0f. Его нелегко применить к другому методу работы. Я подозреваю, что у большинства людей этой проблемы нет, и сравнение точного числа с плавающей запятой, вероятно, является ошибкой, поэтому я включаю его в список по умолчанию.-Wold-style-cast
имеет много ложных срабатываний в коде библиотеки, который я использую. В частности, семейство функций htonl, используемых в сети, а также реализация шифрования Rijndael (AES), которую я использую, имеют приведения в старом стиле, о которых меня предупреждают. Я намерен заменить оба из них, но я не уверен, есть ли в моем коде что-то еще, на что он будет жаловаться. Однако большинству пользователей, вероятно, следует включить его по умолчанию.-Wsign-conversion
был трудным (и почти не попал в список). Включение его в моем коде генерировало огромное количество предупреждений (более 100). Почти все они были невиновны. Тем не менее, я старался использовать целые числа со знаком там, где я не был уверен, хотя для моей конкретной проблемной области я обычно получал небольшое повышение эффективности с использованием значений без знака из-за большого количества целочисленных делений, которые я делаю. Я пожертвовал этой эффективностью, потому что был обеспокоен случайным преобразованием целого числа со знаком в беззнаковое с последующим делением (что небезопасно, в отличие от сложения, вычитания и умножения). Включение этого предупреждения позволило мне безопасно изменить большинство моих переменных на беззнаковые типы и добавить несколько приведений в некоторых других местах. В настоящее время это немного сложно использовать, потому что предупреждение не так умно. Например, если вы сделаетеunsigned short + (integral constant expression)
, этот результат неявно повышается до int. Затем он предупреждает о потенциальной проблеме со знаком, если вы присвоите это значениеunsigned
илиunsigned short
, даже если это безопасно. Это определенно самое необязательное предупреждение почти для всех пользователей.-Wsign-promo
: см-Wsign-conversion
.-Wswitch-default
кажется бессмысленным (вам не всегда нужен вариант по умолчанию, если вы явно перечислили все возможности). Однако включение этого предупреждения может привести к тому, что это, вероятно, хорошая идея. В случаях, когда вы явно хотите игнорировать все, кроме перечисленных возможностей (но возможны другие числа), введитеdefault: break;
чтобы сделать это явным. Если вы явно перечисляете все возможности, то включение этого предупреждения поможет убедиться, что вы указали что-то вроде assert (false), чтобы убедиться, что вы действительно охватили все возможные варианты. Это позволяет вам четко указать, в чем состоит ваша проблема, и программно обеспечивает это. Однако вам нужно быть осторожным, просто вставляя везде assert (false). Это лучше, чем ничего не делать со случаем по умолчанию, но, как обычно с assert, он не будет работать в сборках выпуска. Другими словами, вы не можете полагаться на него для проверки чисел, которые вы получаете, скажем, от сетевого подключения или базы данных, над которой у вас нет абсолютного контроля. Исключения или досрочное возвращение - лучший способ справиться с этим (но все же требуется, чтобы у вас был случай по умолчанию!).-Werror
для меня важен. При компиляции большого количества кода в многопоточной сборке с несколькими целями предупреждение легко пропустить. Превращение предупреждений в ошибки гарантирует, что я их замечу.Затем есть набор предупреждений, которые не включены в приведенный выше список, потому что я не нашел их полезными. Это предупреждения и мои комментарии о том, почему я не включаю их в список по умолчанию:
Предупреждения, которые отсутствуют:
-Wabi
не нужен, потому что я не комбинирую двоичные файлы из разных компиляторов. Я все равно пытался скомпилировать с ним, но он не сработал, поэтому он не кажется излишне многословным.-Waggregate-return
это не то, что я считаю ошибкой. Например, он срабатывает при использовании цикла for на основе диапазона для вектора классов. Оптимизация возвращаемого значения должна позаботиться о любых негативных последствиях этого.-Wconversion
триггеры для этого кода:short n = 0; n += 2;
неявное преобразование в int вызывает предупреждение, когда оно затем преобразуется обратно в свой целевой тип.-Weffc++
включает предупреждение, если все элементы данных не инициализированы в списке инициализаторов. Во многих случаях я намеренно не делаю этого, поэтому набор предупреждений слишком загроможден, чтобы быть полезным. Тем не менее, полезно время от времени включать и сканировать другие предупреждения (например, не виртуальные деструкторы базовых классов). Это было бы более полезно в качестве набора предупреждений (например,-Wall
), а не отдельного предупреждения.-Winline
отсутствует, потому что я не использую ключевое слово inline в целях оптимизации, просто для определения функций, встроенных в заголовки. Меня не волнует, действительно ли оптимизатор встраивает его. Это предупреждение также указывает на то, что не может встроить функцию, объявленную в теле класса (например, пустой виртуальный деструктор).-Winvalid-pch
отсутствует, потому что я не использую предварительно скомпилированные заголовки.-Wmissing-format-attribute
не используется, потому что я не использую расширения GNU. То же самое для-Wsuggest-attribute
и некоторых другихПотенциально примечателен своим отсутствием
-Wno-long-long
, в котором я не нуждаюсь. Я компилирую-std=c++0x
(-std=c++11
в GCC 4.7), который включаетlong long
целочисленные типы. Те, кто застрял на C ++ 98 / C ++ 03, могут подумать о добавлении этого исключения из списка предупреждений.-Wnormalized=nfc
уже является вариантом по умолчанию и выглядит лучшим.-Wpadded
время от времени включается для оптимизации компоновки классов, но не остается включенным, потому что не все классы имеют достаточно элементов для удаления отступов в конце. Теоретически я мог бы получить несколько дополнительных переменных «бесплатно», но это не стоит дополнительных усилий по их поддержанию (если размер моего класса изменится, будет нелегко удалить эти ранее свободные переменные).-Wstack-protector
не используется, потому что я не использую-fstack-protector
-Wstrict-aliasing=3
включен-Wall
и является наиболее точным, но похоже, что уровни 1 и 2 дают больше предупреждений. Теоретически более низкий уровень является «более сильным» предупреждением, но это происходит за счет большего количества ложных срабатываний. Мой собственный тестовый код аккуратно скомпилирован на всех трех уровнях.-Wswitch-enum
поведение не то, что я хочу. Я не хочу явно обрабатывать каждый оператор switch. Было бы полезно, если бы в языке был какой-то механизм для активации этого в определенных операторах switch (чтобы гарантировать, что будущие изменения в перечислении обрабатываются везде, где они должны быть), но это излишне для параметра «все или ничего».-Wunsafe-loop-optimizations
вызывает слишком много ложных предупреждений. Может быть полезно применять его периодически и вручную проверять результаты. Например, это предупреждение было сгенерировано в моем коде, когда я перебирал все элементы вектора, чтобы применить к ним набор функций (используя цикл for на основе диапазона). Это также предупреждение для конструктора константного массива const std :: string (где это не цикл в пользовательском коде).-Wzero-as-null-pointer-constant
и-Wuseless-cast
являются предупреждениями только для GCC-4.7, которые я добавлю при переходе на GCC 4.7.Я подал несколько отчетов об ошибках / запросов на улучшение в gcc в результате некоторых из этих исследований, поэтому, надеюсь, я смогу в конечном итоге добавить больше предупреждений из списка «не включать» в список «включить» , Этот список включает все предупреждения, упомянутые в этой теме (плюс, я думаю, несколько дополнительных). Многие из предупреждений, явно не упомянутых в этом сообщении, включены как часть другого предупреждения, о котором я упоминаю. Если кто-нибудь заметит какие-либо предупреждения, которые полностью исключены из этого сообщения, дайте мне знать.
edit: Похоже, я пропустил несколько (которые я теперь добавил). На самом деле есть вторая страница http://gcc.gnu.org, которая довольно хорошо скрыта. Общие параметры предупреждения и опция C ++ (прокрутите вниз до нижней части для предупреждения)
источник
-Wswitch-enum
предупреждает, если вы явно не обрабатываете каждое значение перечисления в переключателе, иdefault
не считается явным. С другой стороны,-Wswitch-default
предупреждает вас, если у вашего коммутатора нетdefault
регистра, даже если вы явно указали все возможные значения.-isystem
вместо-I
«старого библиотечного кода», чтобы предотвратить все эти ложные срабатыванияОоо, все мои первоначальные поисковые запросы привели к 99% сообщений о том, как подавлять предупреждения (что довольно пугающе), но я только что наткнулся на этот комментарий , в котором есть этот прекрасный набор флагов (некоторые менее актуальны):
Перекрестно проверено:
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Так что я думаю, что это хорошая отправная точка. Не осознавал, что это обман, но, по крайней мере, это было глубоко похоронено. :-)
источник
-Wall
не происходит того, чего можно ожидать. Но спасибо, некоторые из них выглядят очень полезными!-Waggregate-return
? Это дает мне предупреждение при каждом использованииbegin/end()
Некоторые из них уже включены в
-Wall
или-Wextra
.Хорошая базовая установка для C:
-std=c99 -pedantic -Wall -Wextra -Wwrite-strings -Werror
и для C ++
-ansi -pedantic -Wall -Wextra -Weffc++
(пропуск
-Werror
для C ++, так как-Weffc++
есть некоторые неудобства)источник
-std=c89
. В режиме C ++ он эквивалентен-std=c++98
. то есть, если вы указываете какой-то другойstd
, не используйтеansi
Пытаться
Это быстрый и грязный старт, который определенно потребует некоторой настройки; во-первых, даже если вы вызовете компилятор по имени, подходящему для вашего языка (например,
g++
для C ++), вы получите предупреждения, которые не относятся к этому языку (и компилятор поднимет руки и откажется продолжать, пока вы убрать предупреждение).Другое дело, что я добавил
-Werror
, потому что, если вы не исправляете предупреждения, зачем вам их включать? Вы также можете убрать предупреждения из списка. (Например, я почти никогда не использую-Waggregate-return
C ++.)Некоторые предупреждения ничего не сделают без других параметров, связанных с производительностью (
-Wstack-protector
).-fdiagnostics-show-option
и руководство GCC - ваши друзья.Кстати, некоторые предупреждения являются взаимоисключающими; в частности, используя
-Wtraditional
и-Wold-style-definition
вместе с-Werror
, не будет компилироваться.источник
В моем Clion's CmakeLists.txt
источник