Недостатки использования флага `-Wextra` при компиляции в GCC
Я знаю, что всегда нужно компилировать с обоими -Wall
а также -Wextra
поскольку они позволяют предупреждения и помогают нам понять нашу ошибку, если таковые имеются.
Я читал, что -Wextra
Флаг компилятора не рекомендуется использовать, потому что он слишком многословен и содержит много ложных срабатываний.
Я был очень удивлен, прочитав это. Так что я начал гуглить, но ответа не получил, так как все результаты поиска были "что делает -Wextra
флаг делать?
Итак, мои вопросы
- В каких ситуациях
-Wextra
флаг испускает ненужные предупреждения? - Можно ли остановить
-Wextra
флаг от включения других флагов, которые заставляют GCC отправлять эти типы предупреждений?
6 ответов
Дело о полезности -Wextra
Предупреждения в том, что соответствующие предупреждения имеют эти свойства (более или менее):
Они генерируют ложные срабатывания.
Ложные срабатывания относительно часты.
Адаптация кода, чтобы избежать ложных срабатываний, является неприятной.
Следствием этого является то, что многие проекты, которые включают -Wall -Wextra
отказаться от попыток избежать всех предупреждений. Следовательно, когда вы компилируете такой проект, вы видите сотни и сотни предупреждений, почти все о допустимом коде. И единственное предупреждение о том, что вы должны были увидеть промахи незамеченными в бесконечном потоке предупреждений. Хуже того: тот факт, что обычная компиляция выдает так много предупреждений, заставляет вас неуклюже избегать новых предупреждений, которые вводит ваш новый код. Как только проект достигает нескольких десятков предупреждений, борьба обычно заканчивается; это потребует героических усилий, чтобы обнулить счетчик предупреждений.
Вот пример некоторого совершенно законного кода, на который лает -Wextra
:
void myClass_destruct(MyClass* me) {}
Это деструктор и он пуст. Тем не менее, это должно быть просто для того, чтобы облегчить вызов его в соответствующих точках (деструкторы подкласса), чтобы было легко добавлять вещи в MyClass
это нуждается в очистке. Тем не мение, -Wextra
будет лаять на неиспользованных me
параметр. Это заставляет программистов писать код так:
void myClass_destruct(MyClass* me) {
(void)me; //shut up the compiler barking about the unused parameter
}
Это обычный шум. И это раздражает писать такой код. Тем не менее, для достижения нулевого количества предупреждений под -Wextra
режим, этот шум должен быть добавлен в код. Итак, вы можете выбрать любые два из этих трех:
Чистый код
Нулевой счетчик предупреждений
-Wextra
предупреждения
Выберите мудро, какой вы хотите бросить, вы не получите все три.
Некоторые из -Wextra
предупреждения приводят в исполнение соответствующий стиль кодирования, который может конфликтовать с процессами некоторых людей. Это единственная причина, чтобы избежать этого. Мое решение в этом случае состоит в том, чтобы "исправить" точный набор, используя -Wno-*
синтаксис.
Например -Wextra
подразумевает -Wempty-body
который предупреждает вас о пустых телах некоторых структур управления, таких как if
, else
а также while
, Но если вы придерживаетесь с одной стороны "итеративного" стиля реализации, а с другой стороны хотите серьезного количества предупреждений, это будет неудобно для вас.
Вот пример развивающегося кода:
void doSomething()
{
if (validatePreConditions())
{
//TODO Handle it some time.
}
// ... Here you have real code.
}
Если у вас есть -Werror
и хотите начать тестирование без проверки предварительных условий, у вас проблемы.
Но здесь есть подводный камень, и то, что приемлемо для кода "в разработке", должно быть исправлено к тому времени, когда код собирается в производство. Так что мой вариант для таких случаев - иметь разный набор предупреждений и разные профили сборки. Так, например, сборка "разработчик" в порядке, чтобы иметь пустые тела, но все, что собирается объединить в основную линию MUST NOT
есть такие пробелы.
Другой пример -Wignored-qualifiers
который входит в -Wextra
, В некоторых случаях вы знаете, компилятор будет игнорировать ваши const
квалификатор, но вы добавляете его только для вашего удобства (лично я не поддерживаю эти классификаторы по типу возврата, но некоторые люди думают, что они хорошо справляются с такими оценками).
В каких ситуациях флаг -Wextra выдает ненужные предупреждения?
Какое у вас определение ненужного? Вы можете обратиться к руководству (это для 4.9.2), чтобы точно узнать, что делают флаги предупреждения. Тогда вы можете сами решить, подходит ли это для вашей кодовой базы.
Можно ли остановить флаг -Wextra от включения других флагов, которые заставляют GCC отправлять эти типы предупреждений?
Придерживаться -Wno-
перед предупреждением, чтобы отключить его. Не все предупреждения имеют флаг предупреждения, что означает, что вам, вероятно, придется придерживаться его. Вы также можете найти дополнительную информацию, просматривая их багтрекер, выполнив поиск определенных флагов предупреждений и выяснив, существуют ли какие-либо обсуждения. Если это не в документации, это может быть там. Разработчики могут также объяснить, почему все так, как есть.
Чтобы ответить на комментарий, который вы указали в комментариях,
... или предупреждения о пропущенных инициализаторах полей (когда вы намеренно инициализируете структуру с помощью { 0 }, заставляя компилятор инициализировать все остальное автоматически).
Этот аргумент является спорным, потому что он уже исправлен. Например, следующий код не выдает предупреждение об отсутствующих полях инициализатора:
typedef struct { int a; int b; } S;
int main()
{
S s = { 0 };
}
Это очень просто;
Бесполезное предупреждение - это предупреждение, которое никогда не указывает на реальную ошибку.
Конечно, это неразрешимо, невозможно заранее знать, будет ли какое-то конкретное предупреждение "спасать бекон".
Все предупреждения GCC в тот или иной момент указывают на реальные ошибки, поэтому общая тема сообщений GCC заключается в том, что -стенные предупреждения могут указывать на ошибки и их легко подавить, если они этого не делают. Так что это хорошо сочетается с -Werror.
Сообщения -Wextra, OTOH, реже указывают на реальные ошибки или могут указывать на конструкции, которые являются обычной практикой в более старом коде или просто трудно перейти на альтернативный способ выражения кода. Поэтому иногда они действительно могут быть "слишком многословными".
Для нового кода вы обычно хотите -Wextra на.
Для старого кода его следует включить, если он не слишком многословен.
Есть в основном три типа предупреждений, и GCC не очень хорош в их группировке или разъяснении:
Предупреждения, которые указывают на что-то формально недопустимое на исходном уровне, которое не должно даже компилироваться, но это разрешено по любой причине (обычно совместимость с унаследованным кодом). Они обязательны для языкового стандарта.
Предупреждения, указывающие на то, что ваша программа обязательно вызовет неопределенное поведение, если достигнет точки в коде, где происходит предупреждение. Ваша программа все еще может быть действительной, если код недоступен, и на самом деле это может произойти с такими вещами, как:
int i = 1; if (INT_MAX > 0x7fffffff) <<= 31;
Предупреждения, которые являются чисто эвристическими и сами по себе не указывают на какую-либо программную ошибку или недействительность вашей программы, когда компилятор просто предупреждает вас о том, что вы, возможно, имели в виду что-то отличное от того, что вы написали.
-Wextra
включает много предупреждений типа 3.
Как правило, все согласны с тем, что типы 1 и 2 являются ценными, но, как уже упоминалось выше, даже тип 2 может иметь ложные срабатывания. Тип 3 обычно имеет много ложных срабатываний; некоторые из них могут быть подавлены безобидными изменениями в коде, в то время как другие требуют, чтобы ваш код ухудшался (или отключал предупреждение локально), чтобы избежать их.
Здесь люди не согласятся. Для некоторых программистов, вы просто включаете -Wall -Wextra
и локально обходить или отключать предупреждения, когда появляются ложные срабатывания. Однако, если вы этого не сделаете, ложные срабатывания создают много шума и потенциально снижают отношение сигнал / шум, заставляя вас не замечать более серьезных предупреждений, привыкая к просмотру предупреждений при компиляции.
Есть (по крайней мере) два лагеря программистов на Си: те, которые думают, что компилятор может иногда знать лучше, и те, кто думает, кто такой компилятор, чтобы сказать мне, как писать мой код, в конце концов, я знаю, что буду делать.
Лагерь 1 позволяет максимально использовать предупреждения, использовать lint и другие средства проверки кода, чтобы даже получить больше подсказок о сомнительном или потенциально испорченном коде.
Лагерь 2 не любит, когда их машина постоянно указывает на неряшливость, не говоря уже о том, чтобы тратить дополнительные усилия на исправление того, что они считают идеальным как есть.
Лагерь 1 востребован в отрасли, потому что он производит меньше глючного кода, меньше дефектов, меньше сообщений об ошибках клиентов. Если вы программируете ракеты-носители, спутниковое оборудование, все, что нуждается в безопасности, управляете действительно дорогостоящим оборудованием, мышление этого лагеря - это то, что нужно.
Очевидно, что Camp 2 слишком часто удаляется, и общее качество программного обеспечения многих приложений, которые вы используете (на вашем компьютере, смартфоне, устройстве, ...), свидетельствует об этом.
К какому лагерю ты хочешь принадлежать? Недостатки -Wextra
зависит от этого ответа. Недостаток одного человека - преимущество другого.