Для контекста, я разработчик Clang, работающий в Google. В Google мы внедрили диагностику Clang (по существу) всем нашим разработчикам на C ++, и мы также рассматриваем предупреждения Clang как ошибки. Как разработчик Clang и один из крупнейших пользователей диагностики Clang, я постараюсь пролить свет на эти флаги и то, как их можно использовать. Обратите внимание, что все, что я описываю, в целом применимо к Clang, а не специфично для C, C ++ или Objective-C.
TL; DR версия: пожалуйста, используйте -Wall
и -Werror
как минимум для любого нового кода, который вы разрабатываете. Мы (разработчики компилятора) добавляем сюда предупреждения по веским причинам: они находят ошибки. Если вы найдете предупреждение, которое ловит вас за ошибки, включите его. Попробуйте -Wextra
здесь кучу хороших кандидатов. Если один из них слишком шумный для вас, чтобы использовать его с выгодой, сообщите об ошибке . Если вы пишете код, который содержит «очевидную» ошибку, но компилятор не предупредил об этом, сообщите об ошибке.
Теперь для длинной версии. Сначала немного информации о группах предупреждений. Существует много группировок предупреждений в Clang (и в ограниченной степени в GCC). Некоторые из них имеют отношение к этой дискуссии:
- По-умолчанию: эти предупреждения всегда включены, если вы явно не отключите их.
-Wall
: Это предупреждение о том , что разработчики имеют высокую уверенность в обеих их стоимости и низком уровне ложно-позитивности.
-Wextra
Это предупреждения, которые считаются ценными и обоснованными (т. Е. Они не содержат ошибок), но могут иметь высокий уровень ложноположительных результатов или общие философские возражения.
-Weverything
Это безумная группа, которая буквально включает каждое
предупреждение в Clang. Не используйте это в своем коде. Он предназначен исключительно для разработчиков Clang или для изучения существующих предупреждений .
Есть два основных критерия, упомянутых выше, которые определяют, куда направляются предупреждения в Clang, и давайте выясним, что они на самом деле означают. Первый - это потенциальная
ценность конкретного появления предупреждения. Это ожидаемое преимущество для пользователя (разработчика), когда предупреждение срабатывает и правильно
определяет проблему с кодом.
Вторым критерием является идея ложноположительных отчетов. Это ситуации, когда предупреждение срабатывает в коде, но потенциальная проблема, о которой идет речь, на самом деле не возникает из-за контекста или другого ограничения программы. Код, о котором предупреждено, на самом деле ведет себя правильно. Это особенно плохо, когда предупреждение никогда не предназначалось для запуска по этому шаблону кода. Напротив, недостаток в реализации предупреждения вызывает его срабатывание.
Для предупреждений Clang это значение должно быть с точки зрения правильности , а не с точки зрения стиля, вкуса или соглашений о кодировании. Это ограничивает набор доступных предупреждений, исключая часто запрашиваемые предупреждения, такие как предупреждение, всякий раз, когда {}
s не используются в теле if
оператора. Clang также очень нетерпим к ложным срабатываниям . В отличие от большинства других компиляторов, он будет использовать невероятное разнообразие источников информации для сокращения ложных срабатываний, включая точное написание конструкции, наличие или отсутствие дополнительных '()', приведений или даже макросов препроцессора!
Теперь давайте возьмем несколько реальных примеров предупреждений от Clang и посмотрим, как они классифицируются. Во-первых, предупреждение по умолчанию:
% nl x.cc
1 class C { const int x; };
% clang -fsyntax-only x.cc
x.cc:1:7: warning: class 'C' does not declare any constructor to initialize its non-modifiable members
class C { const int x; };
^
x.cc:1:21: note: const member 'x' will never be initialized
class C { const int x; };
^
1 warning generated.
Здесь не требуется флаг, чтобы получить это предупреждение. Обоснование состоит в том, что этот код никогда не является действительно правильным, давая высокое значение предупреждения , и предупреждение срабатывает только на коде, который Clang может доказать, попадает в этот сегмент, давая ему нулевой уровень ложных срабатываний .
% nl x2.cc
1 int f(int x_) {
2 int x = x;
3 return x;
4 }
% clang -fsyntax-only -Wall x2.cc
x2.cc:2:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
int x = x;
~ ^
1 warning generated.
Clang требует -Wall
флаг для этого предупреждения. Причина в том, что существует нетривиальный объем кода, который использовал (хорошо или плохо) шаблон кода, о котором мы предупреждаем, чтобы преднамеренно создать неинициализированное значение. С философской точки зрения, я не вижу в этом смысла, но многие другие не согласны, и реальность этого разногласия заключается в том, что движет предупреждением под
-Wall
флагом. Он по-прежнему имеет очень высокое значение и очень низкий уровень
ложноположительных результатов , но на некоторых кодовых базах он не является стартовым.
% nl x3.cc
1 void g(int x);
2 void f(int arr[], unsigned int size) {
3 for (int i = 0; i < size; ++i)
4 g(arr[i]);
5 }
% clang -fsyntax-only -Wextra x3.cc
x3.cc:3:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
for (int i = 0; i < size; ++i)
~ ^ ~~~~
1 warning generated.
Это предупреждение требует -Wextra
флажка. Причина в том, что существуют очень
большие кодовые базы, в которых несоответствующий знак сравнений встречается крайне часто. Хотя это предупреждение обнаруживает некоторые ошибки, вероятность того, что код будет ошибкой, когда пользователь пишет, в среднем достаточно низкая. Результатом является чрезвычайно высокий уровень ложноположительных результатов . Тем не менее, когда в программе есть ошибка из-за странных правил продвижения, часто очень трудно сделать это предупреждение,
когда она отмечает ошибку , имеющую относительно высокое значение . Как следствие, Clang предоставляет это и выставляет это под флагом.
Как правило, предупреждения не живут долго вне -Wextra
флага. Clang очень старается не реализовывать предупреждения, которые не видят регулярного использования и тестирования. Дополнительные предупреждения, включенные -Weverything
обычно, являются предупреждениями при активной разработке или с активными ошибками. Либо они будут исправлены и помещены под соответствующие флаги, либо они должны быть удалены.
Теперь, когда у нас есть понимание того, как эти вещи работают с Clang, давайте попробуем вернуться к первоначальному вопросу: какие предупреждения вы должны включить для своего развития? Ответ, к сожалению, зависит от этого. Примите во внимание следующие вопросы, чтобы определить, какие предупреждения лучше всего подходят для вашей ситуации.
- Есть ли у вас контроль над всем вашим кодом, или часть его является внешним?
- Каковы твои цели? Ловить ошибки или писать лучший код?
- Какова ваша ложноположительная терпимость? Готовы ли вы написать дополнительный код для регулярного отключения предупреждений?
Прежде всего, если вы не контролируете код, не пытайтесь включить туда дополнительные предупреждения. Будьте готовы выключить некоторые. В мире много плохого кода, и вы не сможете исправить все это. Все в порядке. Старайтесь найти способ сосредоточить свои усилия на коде, которым вы управляете.
Затем выясните, что вы хотите из своих предупреждений. Это разные для разных людей. Clang попытается предупредить без каких-либо опций о вопиющих ошибках или шаблонах кода, для которых у нас есть давний исторический прецедент, указывающий, что уровень ошибок чрезвычайно высок. Благодаря этому -Wall
вы получите гораздо более агрессивный набор предупреждений, направленных на выявление наиболее распространенных ошибок, которые разработчики Clang наблюдали в коде C ++. Но с обоими из них уровень
ложноположительных результатов должен оставаться довольно низким.
Наконец, если вы абсолютно готовы замолчать * ложноположительные * на каждом шагу, сделайте это -Wextra
. Сообщайте об ошибках, если вы замечаете предупреждения, которые содержат много реальных ошибок, но имеют ложные или бессмысленные ложные срабатывания. Мы постоянно работаем , чтобы найти способы , чтобы принести больше и больше ошибок ознакомительной логики представить в -Wextra
в -Wall
где мы можем избежать ложных срабатываний.
Многие найдут, что ни один из этих вариантов не подходит именно им. В Google мы отключили некоторые предупреждения -Wall
из-за большого количества существующего кода, который нарушил предупреждение. Мы также включили некоторые предупреждения явно, хотя они не включены -Wall
, потому что они имеют для нас особенно высокую ценность. Ваш пробег будет варьироваться, но, вероятно, будет меняться аналогичным образом. Часто бывает гораздо лучше включить несколько ключевых предупреждений, а не все
-Wextra
.
Я бы посоветовал всем включить -Wall
любой не устаревший код. Для нового кода предупреждения здесь почти всегда полезны и действительно улучшают опыт разработки кода. И наоборот, я бы посоветовал всем
не включать флаги за пределами -Wextra
. Если Вы нашли предупреждение Clang , что -Wextra
не включает в себя , но который оказывается совсем ценным для вас, просто файл ошибки , и мы , вероятно , можем поставить его под -Wextra
. Если вы явно включите какое-то подмножество предупреждений, -Wextra
будет сильно зависеть от вашего кода, вашего стиля кодирования и от того, проще ли поддерживать этот список, чем исправить все, что было обнаружено -Wextra
.
Из списка предупреждений OP (который включает оба -Wall
и -Wextra
) только следующие предупреждения не охватываются этими двумя группами (или включены по умолчанию). Первая группа подчеркивает, почему чрезмерная зависимость от флагов явного предупреждения может быть плохой: ни один из них даже не реализован в Clang! Они принимаются в командной строке только для совместимости с GCC.
-Wbad-function-cast
-Wdeclaration-after-statement
-Wmissing-format-attribute
-Wmissing-noreturn
-Wnested-externs
-Wnewline-eof
-Wold-style-definition
-Wredundant-decls
-Wsequence-point
-Wstrict-prototypes
-Wswitch-default
Следующее множество ненужных предупреждений в исходном списке - это те, которые являются избыточными с другими в этом списке:
-Wformat-nonliteral
- Подмножество -Wformat=2
-Wshorten-64-to-32
- Подмножество -Wconversion
-Wsign-conversion
- Подмножество -Wconversion
Есть также выбор предупреждений, которые более категоричны. Они имеют дело с вариантами языкового диалекта, а не с ошибочным или не ошибочным кодом. За исключением того -Wwrite-strings
, что все это предупреждения для языковых расширений, предоставляемых Clang. Предупреждает ли Clang об их использовании, зависит от распространенности расширения. Clang стремится к совместимости с GCC, и поэтому во многих случаях облегчает это с помощью неявных языковых расширений, которые широко используются. -Wwrite-strings
Как прокомментировал OP, это флаг совместимости от GCC, который фактически изменяет семантику программы. Я глубоко сожалею об этом флаге, но мы должны поддержать его из-за наследия, которое оно имеет сейчас.
-Wfour-char-constants
-Wpointer-arith
-Wwrite-strings
Остальные опции, которые фактически включают потенциально интересные предупреждения, таковы:
-Wcast-align
-Wconversion
-Wfloat-equal
-Wformat=2
-Wimplicit-atomic-properties
-Wmissing-declarations
-Wmissing-prototypes
-Woverlength-strings
-Wshadow
-Wstrict-selector-match
-Wundeclared-selector
-Wunreachable-code
Причина, по которой они отсутствуют -Wall
или -Wextra
не всегда понятна. Для многих из них, на самом деле они основаны на предупреждения GCC ( -Wconversion
,
-Wshadow
и т.д.) и как таковой Clang пытается имитировать поведение GCC в. Мы постепенно разбиваем некоторые из них на более мелкие и полезные предупреждения. Те, у кого больше шансов попасть в одну из групп предупреждений верхнего уровня. Тем не менее, чтобы выбрать одно предупреждение, -Wconversion
оно настолько широко, что в обозримом будущем оно, скорее всего, останется своей собственной категорией «высшего уровня». Некоторые другие предупреждения, которые имеет GCC, но которые имеют низкую ценность и высокий уровень ложноположительных результатов, могут быть отнесены к аналогичной ничейной земле.
Другие причины, по которым их нет в одной из больших групп, включают в себя простые ошибки, очень существенные ложноположительные проблемы и предупреждения в процессе разработки. Я собираюсь изучить ошибки, которые я могу определить. Все они в конечном итоге должны перейти в соответствующий большой флаг или быть удалены из Clang.
Я надеюсь, что это проясняет ситуацию с предупреждениями в Clang и дает некоторую информацию для тех, кто пытается выбрать набор предупреждений для их использования или использования их компанией.