Почему я всегда должен включать предупреждения компилятора?


302

Я часто слышу, что при компиляции программ на C и C ++ я должен «всегда включать предупреждения компилятора». Почему это необходимо? Как я могу это сделать?

Иногда я также слышу, что я должен «воспринимать предупреждения как ошибки». Нужно ли мне? Как я могу это сделать?

Ответы:


341

Зачем включать предупреждения?

Компиляторы C и C ++, как известно, плохо по умолчанию сообщают о некоторых распространенных ошибках программиста , таких как:

  • забыв инициализировать переменную
  • забывать returnзначение из функции
  • аргументы printfи scanfсемейства, не соответствующие строке формата
  • функция используется без предварительного объявления (только C)

Они могут быть обнаружены и зарегистрированы, но обычно не по умолчанию; эта функция должна быть явно запрошена через параметры компилятора.

Как включить предупреждения?

Это зависит от вашего компилятора.

Microsoft C и C ++ компиляторы понимать переключатели нравится /W1, /W2, /W3, /W4и /Wall. Используйте по крайней мере /W3. /W4и /Wallможет выдавать ложные предупреждения для системных заголовочных файлов, но если ваш проект корректно компилируется с помощью одного из этих параметров, сделайте это. Эти параметры являются взаимоисключающими.

Большинство других компиляторов понимают такие опции , как -Wall, -Wpedanticи -Wextra. -Wallявляется необходимым, и все остальные рекомендуются (обратите внимание, что, несмотря на его название, -Wallвключает только самые важные предупреждения, а не все ). Эти параметры можно использовать отдельно или все вместе.

Ваша IDE может иметь возможность включить их из пользовательского интерфейса.

Зачем воспринимать предупреждения как ошибки? Это просто предупреждения!

Предупреждение компилятора сигнализирует о потенциально серьезной проблеме в вашем коде. Проблемы, перечисленные выше, почти всегда являются фатальными; другие могут или не могут быть, но вы хотите, чтобы компиляция не удалась, даже если это ложная тревога. Изучите каждое предупреждение, найдите причину и устраните ее. В случае ложной тревоги обойдите ее, то есть используйте другую языковую функцию или конструкцию, чтобы предупреждение больше не срабатывало. Если это окажется очень сложно, отключите это конкретное предупреждение в каждом конкретном случае.

Вы не хотите просто оставлять предупреждения как предупреждения, даже если все они ложные тревоги. Это может быть хорошо для очень маленьких проектов, где общее количество отправленных предупреждений меньше 7. Все больше, и новое предупреждение легко потеряться в потоке старых знакомых. Не позволяй этого. Просто заставьте весь ваш проект скомпилировать чисто.

Обратите внимание, что это относится к разработке программ. Если вы публикуете свой проект для мира в исходной форме, то может быть хорошей идеей не указывать или не указывать -Werrorэквивалент в выпущенном скрипте сборки. Люди могут попытаться построить ваш проект с другой версией компилятора или с другим компилятором, у которого может быть включен другой набор предупреждений. Вы можете хотеть, чтобы их сборка была успешной. По-прежнему рекомендуется включать предупреждения, чтобы люди, которые видят предупреждающие сообщения, могли отправлять вам сообщения об ошибках или исправления.

Как воспринимать предупреждения как ошибки?

Это снова сделано с переключателями компилятора. /WXдля Microsoft, большинство других используют -Werror. В любом случае компиляция не удастся, если появятся какие-либо предупреждения.


107
Я разместил этот вопрос и ответ, потому что мне надоело рассказывать людям, чтобы они включали предупреждения. Теперь я могу просто указать их здесь (или, если я нахожусь в особенно дурном настроении, закрыть их вопрос как обман). Вы можете улучшить этот ответ или добавить свой собственный!
нет. местоимения м.

16
Вы также можете использовать Clang's -Weverything
pmg

9
Единственный модификатор, который я бы добавил, состоит в том, что некоторые предупреждения могут быть бесполезны для вашего приложения. (Я видел предупреждения о том, что компилятор добавил 2 байта заполнения между элементами в структуре. Приложение предназначено для создания прототипов, поэтому немного потраченной впустую памяти нас не беспокоило.) Обрабатывайте все предупреждения как ошибки, а затем отключайте только предупреждение, если Вы знаете, почему это предупреждение не поможет вам.
Кайл,

20
Недостатком обработки предупреждений как ошибок для людей, следующих вашим инструкциям по умолчанию, является то, что ваш код гниет, когда компиляторы добавляют новые предупреждения. Пользователи, которые скачивают ваш код и пытаются построить его в будущем, могут этого не сделать, потому что их компилятор слишком новый и выдает предупреждение о некоторых дополнительных скобках или о чем-то, что не заботит ваш компилятор. Пользователь, который обнаружил ошибку, не несет ответственности за ваш код или систему сборки и не знает, как отключить обработку предупреждений как ошибок и фактически построить ваш проект.
Интерфект

15
@interfect Да, это случилось со мной пару раз. Нет, важная персона Если вы решили создать не поддерживаемый фрагмент программного обеспечения с использованием компилятора, с которым он никогда не тестировался, то лучше подготовьтесь к самостоятельному обслуживанию.
нет. местоимения м.

94

C, как известно, является языком довольно низкого уровня, как и HLL. C ++, хотя может показаться, что это язык значительно более высокого уровня, чем C, все же разделяет ряд своих особенностей. И одна из этих черт заключается в том, что языки были разработаны программистами для программистов - и, в частности, программистов, которые знали, что они делают.

[В остальной части этого ответа я собираюсь сосредоточиться на C. Большая часть того, что я скажу, также относится к C ++, хотя, возможно, не так сильно. Хотя, как сказал Бьярн Страуструп, «С позволяет легко выстрелить себе в ногу; С ++ делает это тяжелее, но когда вы делаете это, вырываете ногу целиком». ]

Если вы знаете, что делаете - действительно знаете, что делаете - иногда вам, возможно, придется «нарушать правила». Но большую часть времени большинство из нас согласятся с тем, что благие намерения не дают нам всех проблем, и что бессмысленное нарушение этих правил все время является плохой идеей.

Но в C и C ++ есть удивительно большое количество вещей, которые вы можете сделать, которые являются «плохими идеями», но формально не «против правил». Иногда они плохие идеи иногда (но могут быть оправданы в других случаях); иногда они плохая идея практически все время. Но традиция всегда состояла в том, чтобы не предупреждать об этих вещах - потому что, опять же, предполагается, что программисты знают, что они делают, они не будут делать эти вещи без веской причины, их будет раздражать куча ненужных предупреждений.

Но, конечно, не все программисты действительно знают, что делают. И, в частности, каждый программист C (независимо от его опыта) проходит этап становления программистом на C. И даже опытные программисты на Си могут быть неосторожны и совершать ошибки.

Наконец, опыт показал не только то, что программисты совершают ошибки, но и что эти ошибки могут иметь реальные серьезные последствия. Если вы допустили ошибку, и компилятор не предупредил вас об этом, и каким-то образом программа не сразу аварийно завершает работу или делает что-то явно неправильное из-за этого, ошибка может скрываться там, скрытая, иногда в течение многих лет, пока не приведет действительно большая проблема.

Получается, что в большинстве случаев предупреждения - хорошая идея. Даже опытные программисты узнали (на самом деле, это « особенно опытные программисты узнали»), что в целом предупреждения имеют тенденцию приносить больше пользы, чем вреда. Каждый раз, когда вы умышленно что-то делали неправильно, а предупреждение было неприятным, вероятно, вы, по крайней мере, десять раз делали что-то неправильно, и предупреждение спасало вас от дальнейших неприятностей. И большинство предупреждений можно отключить или обойти для тех немногих случаев, когда вы действительно хотите сделать «не то».

(Классический пример такой «ошибка» является тестом if(a = b)Большой части времени, это ошибка, поэтому большинство компиляторов этих дней предупредят об этом. -. Некоторые даже по умолчанию Но если вы действительно хотели как правопреемник bк aи испытанию В результате вы можете отключить предупреждение, набрав if((a = b)).)

Второй вопрос: почему вы хотите попросить компилятор рассматривать предупреждения как ошибки? Я бы сказал, что это из-за человеческой природы, в частности, слишком простой реакции: «О, это просто предупреждение, это не так важно, я уберу это позже». Но если вы прокрастинатор (и я не знаю о вас, но я ужасный прокрастинатор), то легко отменить обязательную очистку практически навсегда - и если вы привыкли игнорировать предупреждения, это становится все легче пропустить важное предупреждающее сообщение, которое находится там, незамеченным, среди всех тех, которые вы игнорируете.

Поэтому попросить компилятор рассматривать предупреждения как ошибки - это небольшая хитрость, которую вы можете сыграть на себе, чтобы обойти эту человеческую слабость.

Лично я не так настойчиво отношусь к обработке предупреждений, как к ошибкам. (На самом деле, если честно, я могу сказать, что я практически никогда не включаю эту опцию в своем «личном» программировании.) Но вы можете быть уверены, что у меня эта опция включена на работе, где наше руководство по стилю (которое я писал) обязывает его использовать. И я бы сказал - я подозреваю, что большинство профессиональных программистов скажут - что любой магазин, который не рассматривает предупреждения как ошибки в C, ведет себя безответственно, не придерживается общепринятых лучших отраслевых практик.


9
«программисты, которые знали, что делают» - LOL; есть ошибка "нет истинного шотландца", если я когда-либо видел ее
Dancrumb

3
@Dancrumb LOL назад атча. Я никогда не уверен, что понимаю ошибку « Нет истинного шотландца» , но мне это нравится, так что это будет хорошим упражнением для меня. Я предполагаю, что приложение здесь выглядит так: «Ни один программист на С никогда не писал бы if(a = b), поэтому нам не нужно об этом предупреждать». (Затем кто-то создает список из 10 критических ошибок в 10 выпущенных продуктах, которые возникают в результате этой конкретной ошибки.) «Хорошо, ни один опытный программист на С никогда не напишет это ...»
Стив Саммит

3
@SteveSummit, но действительно опытный программист на C может написать if (returnCodeFromFoo = foo(bar))и сказать это, чтобы захватить и протестировать код в одном месте (Предположим, единственная цель foo- иметь побочные эффекты!) Тот факт, что действительно опытный программист может знать, что это не хороший стиль кодирования не имеет значения;)
alephzero

5
Дело в том, что большинство очень опытных программистов включают большинство, если не все, предупреждения. Если они хотят использовать что-то подобное if (returnCodeFromFoo = foo(bar)), то они добавляют комментарий и отключают предупреждение (чтобы программист по техническому обслуживанию посмотрел на него 4 года спустя, он / она осознал, что код был намеренным. Тем не менее, я работал с кем-то, кто в (в Microsoft C ++ land) настаивал на том, что объединение / Wall с обработкой предупреждений как ошибок - это путь. Э-э, это не так (если только вы не хотите добавить много комментариев подавления).
Flydog57

3
Как человек, который не пишет код ежедневно, но когда я делаю это, как правило, голый металл (часто на доске моего собственного дизайна), я считаю предупреждения бесценными. При вставке значений во внутренние регистры (например, для местоположения дескриптора DMA) предупреждение о преобразовании в указатель означает, что я выполняю приведение для сброса предупреждения. Это не будет ошибкой, но если кто-то (или даже я!) Заберет этот код через несколько месяцев, это может привести к путанице. Кроме того, я применяю правило отсутствия предупреждений и к выводам моих инструментов CAD.
Питер Смит

39

Предупреждения состоят из лучших советов, которые некоторые из наиболее опытных разработчиков C ++ могут испечь в приложении. Их стоит держать рядом.

C ++, будучи полным языком Тьюринга, имеет множество случаев, когда компилятор должен просто поверить, что вы знали, что делаете. Однако во многих случаях компилятор может понять, что вы, вероятно, не намеревались писать то, что написали. Классическим примером являются коды printf (), которые не соответствуют аргументам, или std :: strings, переданные в printf (не то, что когда-либо случалось со мной!). В этих случаях написанный вами код не является ошибкой. Это допустимое выражение C ++ с допустимой интерпретацией для действия компилятора. Но у компилятора есть сильное предчувствие, что вы просто пропустили что-то, что легко обнаруживается современным компилятором. Это предупреждения. Это те вещи, которые очевидны для компилятора, использующего все строгие правила С ++, которые вы могли бы игнорировать.

Отключать предупреждения или игнорировать их - все равно что игнорировать бесплатные советы от тех, кто более опытен, чем вы. Это урок huberis, который заканчивается, когда вы летите слишком близко к солнцу и ваши крылья тают, или возникает ошибка повреждения памяти. Между этими двумя я буду падать с неба в любой день!

«Рассматривать предупреждения как ошибки» - крайняя версия этой философии. Идея заключается в том, что вы разрешаете каждое предупреждение, которое дает вам компилятор - вы слушаете каждый бесплатный совет и действуете в соответствии с ним. Является ли это хорошей моделью для развития, зависит от команды и от того, над каким продуктом вы работаете. Это аскетический подход, который мог бы иметь монах. Для некоторых это прекрасно работает. Для других это не так.

Во многих моих приложениях мы не рассматриваем предупреждения как ошибки. Мы делаем это, потому что эти конкретные приложения должны компилироваться на нескольких платформах с несколькими компиляторами разного возраста. Иногда мы обнаруживаем, что на самом деле невозможно зафиксировать предупреждение на одной стороне, не превратив его в предупреждение на другой платформе. Так что мы просто осторожны. Мы уважаем предупреждения, но не загибаемся за них.


11
То, что С ++ является завершенным по Тьюрингу, связано с этим. Многие языки завершены и не доверяют вам, если вы делаете что-то не так ...
До свидания SE

3
@KamiKaze каждый язык будет иметь идиоматические ошибки (например, Java не может помешать вам писать противоречивые equals/ hashCode), и это вопрос качества реализации, о которых сообщается.
Caleth

2
@KamiKaze Бит завершенности Тьюринга показывает, что существуют случаи, когда компилятор не может доказать, что ваш код не будет работать как запланировано. Это важно, потому что компиляторы не могут сделать весь «неправильный» код ошибкой. Ошибки могут быть зарезервированы только для поведения, которое, как уверены разработчики языка, всегда будет «неправильным». (как правило, потому что это ведет по непоследовательным путям).
Корт Аммон

2
Что также указывает на проблему с «все предупреждения являются ошибками». Предупреждения, по своему замыслу, являются более гибкими, вызывая потенциально некорректный код в обмен на более частый запуск неправильного кода. Предупреждения как ошибки приводят к тому, что вы не можете использовать все возможности языка.
Cort Ammon

2
Тем не менее, в общем, программисты хотят язык, который делает больше, чем «безопасная» вещь. Нам нужен язык, который делает то, что, как мы думали, мы ему сказали. Таким образом, предупреждения остаются важными, потому что фактический класс вещей, которые мы хотим, чтобы компьютер делал, является семантическим классом. Компилятор может выбрать это, определив «неправильный» или «небезопасный», но в конце концов у вас все еще есть суперкласс поведения, которое программист хотел, чтобы программа выполняла. Предупреждения помогают сузить этот суперкласс.
Корт Аммон

19

Обработка предупреждений не только улучшает код, но и делает программиста лучше. Предупреждения расскажут вам о вещах, которые сегодня могут показаться вам незначительными, но однажды эта дурная привычка вернется и откусит вам голову.

Используйте правильный тип, верните это значение, оцените это возвращаемое значение. Потратьте время и подумайте: «Действительно ли это правильный тип в этом контексте?» "Мне нужно вернуть это?" И важная персона; «Будет ли этот код переносимым на следующие 10 лет?»

Привыкайте писать код без предупреждения.


17

Другие ответы превосходны, и я не хочу повторять то, что они сказали.

Еще один аспект «зачем включать предупреждения», который не был должным образом затронут, заключается в том, что они чрезвычайно помогают в обслуживании кода. Когда вы пишете программу значительного размера, становится невозможным держать все это в голове сразу. Обычно у вас есть функция или три, о которых вы активно пишете и думаете, и, возможно, файл или три на вашем экране, к которым вы можете обратиться, но основная часть программы находится где-то в фоновом режиме, и вы должны верить, что она продолжает работать.

Наличие предупреждений и наличие их как можно более энергичных и на вашем лице помогает предупредить вас, если что-то, что вы меняете, создает проблемы для чего-то, что вы не можете видеть.

Взять, к примеру, предупреждение лязг -Wswitch-enum . Это вызывает предупреждение, если вы используете переключатель enum и пропускаете одно из возможных значений enum. Вы можете подумать, что это будет маловероятной ошибкой: вы, по крайней мере, смотрели на список значений enum, когда писали оператор switch. У вас может даже быть IDE, которая генерирует параметры переключения для вас, не оставляя места для человеческой ошибки.

Это предупреждение действительно вступает в силу, когда через шесть месяцев вы добавляете еще одну возможную запись в перечисление. Опять же, если вы думаете о рассматриваемом коде, вы, вероятно, будете в порядке. Но если это перечисление используется для нескольких разных целей и для одной из тех, кому вам нужна дополнительная опция, очень легко забыть обновить переключатель в файле, к которому вы не обращались в течение 6 месяцев.

Вы можете думать о предупреждениях так же, как и об автоматизированных тестовых случаях: они помогают вам убедиться в том, что код имеет смысл, и делают то, что вам нужно, когда вы впервые пишете его, но еще больше помогают убедиться, что он продолжает делать то, что вам нужно, пока вы толкаете на это. Разница в том, что контрольные примеры работают очень близко к требованиям вашего кода, и вы должны их писать, в то время как предупреждения работают в широком смысле в соответствии с разумными стандартами почти для всего кода, и они очень щедро поставляются блоками, которые создают компиляторы.


9
Другой способ, которым они помогают с обслуживанием, - это когда вы смотрите на чужой код и не можете сказать, был ли побочный эффект преднамеренным. С предупреждениями вы знаете, что они хотя бы знали о проблеме.
Робин Беннетт

Или, в моем случае, вы импортируете файл из встроенной системы, который содержит более 3000 операторов строкового переключателя над перечислением с несколькими тысячами значений. Предупреждения «проваливаются» (их можно избежать с помощью goto) маскируют ряд «не обработанных» ошибок ... встроенный компилятор не выдает ни одного из них, но, тем не менее, ошибки были важны.
19

15

Нефиксированные предупреждения рано или поздно приведут к ошибкам в вашем коде .


Например, для отладки ошибки сегментации программист должен отследить корень (причину) ошибки, которая обычно находится в вашем коде раньше, чем строка, которая в конечном итоге вызвала ошибку сегментации.

Очень типично, что причиной является строка, для которой компилятор выдал предупреждение, которое вы проигнорировали, и строка, которая вызвала ошибку сегментации, строка, которая в конечном итоге вызвала ошибку.

Исправление предупреждения приводит к решению проблемы. Классика!

Демонстрация вышесказанного. Рассмотрим следующий код:

#include <stdio.h>

int main(void) {
  char* str = "Hello world!";
  int idx;

  // Colossal amount of code here, irrelevant to 'idx'

  printf("%c\n", str[idx]);

  return 0;
}

который при компиляции с флагом "Wextra" передается в GCC, дает:

main.c: In function 'main':
main.c:9:21: warning: 'idx' is used uninitialized in this function [-Wuninitialized]
    9 |   printf("%c\n", str[idx]);
      |                     ^

который я мог проигнорировать и выполнить код в любом случае ... И тогда я был бы свидетелем "грандиозной" ошибки сегментации, как говаривал мой профессор IP-эпикура:

Ошибка сегментации

Чтобы отладить это в сценарии реального мира, нужно начать со строки, которая вызывает ошибку сегментации, и попытаться выяснить, в чем причина. Они должны будут искать то, что случилось, iиstr этим колоссальным количеством внутри него. кода там ...

Пока однажды они не оказались в ситуации, когда они обнаруживают, что idx используется неинициализированный, то есть он имеет мусорное значение, что приводит к индексации строки (пути) за ее пределами, что приводит к ошибке сегментации.

Если бы только они не проигнорировали предупреждение, они бы сразу нашли ошибку!


4
К вашему названию: не обязательно. Например, предупреждение, предлагающее использовать скобки в формуле, которая действительно не нуждается в них, указывает на проблему, которая никогда не вызовет ошибку. Приоритеты операторов в данном языке программирования не меняются. Когда-либо.
Марк ван Леувен

4
@MarcvanLeeuwen Пример, который вы цитируете, может обернуться ошибкой, например, если программист, который не помнит приоритет оператора, немного модифицирует формулу. Предупреждение говорит вам: «кому-то может быть непонятно, добавьте несколько скобок, чтобы сделать его более понятным». Хотя надо согласиться, что название оригинального поста не всегда верно.
Юбер Ясенецки

^ Все может быть превращено в ошибку. Так же легко ввести ошибку в частично заключенный в скобки код, как и в полностью заключенный в скобки код.
Джим Балтер

... Кроме того, у меня есть вопросы к отладчику, чья первая реакция на "О, это произошло из-за str[idx]" не "Ладно, где strи что idxопределено?`
Джастин Тайм - Восстановить Монику

2
Вам повезло, если вы получили ошибку сегментации. Если вам повезло меньше, вы можете случайно получить idxзначение, которое вы ожидали в своем тесте (не слишком маловероятно, если ожидаемое значение равно 0), и фактически указывать на некоторые конфиденциальные данные, которые никогда не следует печатать при развертывании.
celtschk

14

Рассматривать предупреждения как ошибки - это всего лишь средство самодисциплины: вы составляли программу для тестирования этой блестящей новой функции, но не можете, пока не исправите неаккуратные детали. Дополнительной информации нет Werror, просто очень четко расставлены приоритеты:

Не добавляйте новый код, пока не исправите проблемы в существующем коде

На самом деле важно мышление, а не инструменты. Вывод диагностики компилятора является инструментом. MISRA (для встроенного C) - еще один инструмент. Неважно, какой из них вы используете, но, возможно, предупреждения компилятора - это самый простой инструмент, который вы можете получить (это только один флаг для установки), а отношение сигнал / шум очень высокое. Так что нет причин не использовать его.

Ни один инструмент не является непогрешимым. Если вы напишите const float pi = 3.14;, большинство инструментов не скажут вам, что вы определили π с плохой точностью, что может привести к проблемам в будущем. Большинство инструментов не вызывают удивления if(tmp < 42), даже если общеизвестно, что присвоение переменных бессмысленным именам и использование магических чисел - это путь к катастрофе в больших проектах. Вы должны понимать, что любой код «быстрого тестирования», который вы пишете, - это просто тест, и вы должны получить его прямо перед тем, как переходить к другим задачам, в то время как вы по-прежнему видите его недостатки. Если вы оставите эти коды как есть, отладка, если по истечении двух месяцев добавление новых функций будет значительно сложнее.

Как только вы попали в правильное мышление, нет смысла использовать Werror. Наличие предупреждений в качестве предупреждений позволит вам принять обоснованное решение, имеет ли смысл запускать тот сеанс отладки, который вы собирались запустить, или прервать его и сначала исправить предупреждения.


3
К лучшему или к худшему, clippyподкладочный инструмент для Rust фактически предупредит о константе «3.14». Это на самом деле пример в документации . Но, как вы можете догадаться из названия, clippyгордится тем, что был агрессивно полезным.
Emk

1
@emk Спасибо за этот пример, возможно, мне следует перефразировать мой ответ в стиле « никогда не говори никогда» . Я не хотел сказать, что проверка на неточные значения π невозможна, просто избавление от предупреждений не гарантирует достойного качества кода.
Дмитрий Григорьев

Предупреждения об ошибках дают вам одну вещь: автоматические сборки будут терпеть неудачу, предупреждая вас о том, что что-то пошло не так. Автоматизированные сборки также позволяют автоматизировать распушение (взрыв 3 ... 2 ... 1 .. :)

8

Как человек, работающий с унаследованным встроенным кодом C, включение предупреждений компилятора помогло выявить множество недостатков и областей, которые необходимо изучить при предложении исправлений. В GCC использование -Wallи -Wextraдаже -Wshadowстали жизненно важными. Я не собираюсь вдаваться в каждую опасность, но перечислю несколько всплывающих, которые помогли показать проблемы с кодом.

Переменные, оставленные позади

Это можно легко указать на незавершенную работу и области, которые могут не использовать все переданные переменные, которые могут быть проблемой. Давайте посмотрим на простую функцию, которая может вызвать это:

int foo(int a, int b)
{
   int c = 0;

   if (a > 0)
   {
        return a;
   }
   return 0;
}

Просто компилирование без -Wall или -Wextra не возвращает никаких проблем. -Все скажет вам, хотя это cникогда не используется:

foo.c: в функции 'foo':

foo.c: 9: 20: предупреждение: неиспользуемая переменная 'c' [-Wunused-variable]

-Wextra также скажет вам, что ваш параметр b ничего не делает:

foo.c: в функции 'foo':

foo.c: 9: 20: предупреждение: неиспользуемая переменная 'c' [-Wunused-variable]

foo.c: 7: 20: предупреждение: неиспользуемый параметр 'b' [-Wunused-параметр] int foo (int a, int b)

Затенение глобальной переменной

Это немного сложно и не показывалось, пока не -Wshadowбыло использовано. Давайте изменим приведенный выше пример, добавив его, но в результате получается глобальный объект с тем же именем, что и локальный, что вызывает путаницу при попытке использовать оба варианта.

int c = 7;

int foo(int a, int b)
{
   int c = a + b;
   return c;
}

Когда -Wshadow был включен, легко обнаружить эту проблему.

foo.c: 11: 9: предупреждение: объявление 'c' затеняет глобальное объявление [-Wshadow]

foo.c: 1: 5: note: теневое объявление здесь

Формат строки

Это не требует каких-либо дополнительных флагов в gcc, но это все еще является источником проблем в прошлом. Простая функция, пытающаяся напечатать данные, но с ошибкой форматирования, может выглядеть так:

void foo(const char * str)
{
    printf("str = %d\n", str);
}

Это не печатает строку, так как флаг форматирования неверен, и gcc с радостью скажет вам, что это, вероятно, не то, что вы хотели:

foo.c: в функции 'foo':

foo.c: 10: 12: предупреждение: формат «% d» ожидает аргумент типа «int», но аргумент 2 имеет тип «const char *» [-Wformat =]


Это всего лишь три из множества вещей, которые компилятор может проверить дважды. Есть много других, таких как использование неинициализированной переменной, на которую указывали другие.


7
Во встроенном мире предупреждения, которые меня больше всего волнуют, - это « possible loss of precision» и « comparison between signed and unsigned» предупреждения. Мне трудно понять, сколько «программистов» их игнорируют (на самом деле, я не совсем уверен, почему они не являются ошибками),
говорит Моуг, верните Монику

3
В последнем случае, @Mawg, я полагаю, что основная причина того, что это не ошибка, заключается в том, что результат sizeofявляется беззнаковым, а целочисленный тип по умолчанию подписан. Тип sizeofрезультата size_t, как правило, используется для всего, что связано с размером шрифта, такого как, например, выравнивание или количество элементов массива / контейнера, тогда как целые числа в целом предназначены для использования как « intесли не требуется иное». Учитывая, как много людей, таким образом, учат использовать intдля перебора своих контейнеров (по сравнению intс size_t), ошибкой было бы сломать почти все. ; P
Джастин Тайм - Восстановить Монику

6

Это конкретный ответ для C, и почему это гораздо важнее для C, чем для чего-либо еще.

#include <stdio.h>
int main()
{
   FILE *fp = "some string";
}

Этот код компилируется с предупреждением . То, что есть и должно быть ошибками практически во всех других языках на планете (за исключением языка ассемблера), является предупреждением на C. Предупреждения на C почти всегда являются замаскированными ошибками. Предупреждения должны быть исправлены, а не подавлены.

С gcc, мы делаем это как gcc -Wall -Werror.

Это также стало причиной высокой вероятности некоторых предупреждений небезопасных API MS. Большинство людей, программирующих на C, научились жестко относиться к предупреждениям как к ошибкам, и казалось, что это не совсем то же самое, и им нужны непереносимые исправления.


5

ПРЕДУПРЕЖДЕНИЯ КОМПИЛЕРА - ВАШ ДРУГ (не кричите, прописные буквы для акцента).

Я работаю на устаревших системах Fortran-77. Компилятор говорит мне ценные вещи: несоответствие типа данных аргумента при вызове подпрограммы с использованием локальной переменной до того, как значение было установлено в переменную, если у меня есть переменная или аргумент подпрограммы, которые не используются. Это почти всегда ошибки.

Избегайте длинных постов: когда мой код компилируется правильно, 97% работает. Другой парень, с которым я работаю, компилирует все предупреждения, проводит часы или дни в отладчике, а затем просит меня помочь. Я просто скомпилировал его код с предупреждениями и сказал ему, что нужно исправить.


5

Вы должны всегда включать предупреждения компилятора, потому что компилятор часто может сказать вам, что не так с вашим кодом. Для этого вы переходите -Wall -Wextraк компилятору.

Обычно вы должны воспринимать предупреждения как ошибки, потому что предупреждения обычно означают, что с вашим кодом что-то не так. Однако часто очень легко игнорировать эти ошибки. Поэтому обработка их как ошибок приведет к сбою сборки, поэтому вы не сможете игнорировать ошибки. Чтобы воспринимать предупреждения как ошибки, перейдите -Werrorк компилятору.


4

Предупреждения компилятора в C ++ очень полезны по ряду причин.

1 - Это позволяет показать вам, где вы могли совершить ошибку, которая может повлиять на конечный результат вашей работы. Например, если вы не инициализировали переменную или вы поставили «=» вместо «==» (есть только примеры)

2 - Позволяет также показать вам, где ваш код не соответствует стандарту C ++. Это полезно, потому что, если код соответствует действующему стандарту, будет легко переместить код, например, в другую табличную форму.

В целом, предупреждения очень полезны, чтобы показать вам, где у вас есть ошибки в вашем коде, которые могут повлиять на результат вашего алгоритма или предотвратить некоторые ошибки, когда пользователь будет использовать вашу программу.


4

Игнорирование предупреждений означает, что вы оставили неаккуратный код, который не только может вызвать проблемы в будущем для кого-то другого, но также сделает важные сообщения компиляции менее заметными для вас. Чем больше выходных данных компилятора, тем меньше кто-нибудь это заметит. Чем чище, тем лучше. Это также означает, что вы знаете, что делаете. Предупреждения очень непрофессиональны, небрежны и рискованны.


4

Однажды я работал в крупной (Fortune 50) компании, которая производила электронное испытательное оборудование.

Основным продуктом моей группы была программа MFC, которая на протяжении многих лет генерировала буквально сотни предупреждений. Которые были проигнорированы почти во всех случаях.

Это ужасный кошмар, когда появляются ошибки.

После этой должности мне посчастливилось быть первым разработчиком в новом стартапе.

Я рекомендовал политику «без предупреждения» для всех сборок, когда уровни предупреждений компилятора были довольно шумными.

Наша практика заключалась в том, чтобы использовать предупреждение #pragma - push / disable / pop для кода, который был уверен, что разработчик был действительно хорош, вместе с оператором log на уровне отладки, на всякий случай.

Эта практика хорошо сработала для нас.


1
Откомандирован. #pragma warningне только подавляет предупреждения, но и выполняет двойную цель - быстро сообщать другим программистам, что что-то является преднамеренным и не случайным, и действует как поисковый тег для быстрого поиска потенциально проблемных областей, когда что-то ломается, но исправление ошибок / предупреждений не почини это.
Джастин Тайм - Восстановить Монику

Ты прав, Джастин, именно так я и посмотрел предупреждение #pragma
Джим в Техасе

3

Предупреждение - ошибка, ожидающая, чтобы случиться. Таким образом, вы должны включить предупреждения компилятора и привести в порядок свой код, чтобы удалить любое предупреждение.


3

Существует только одна проблема с обработкой предупреждений как с ошибками: когда вы используете код, поступающий из других источников (например, микро $ ** t-библиотек, проектов с открытым исходным кодом), они не справились со своей работой правильно, а компиляция их кода генерирует тонны предупреждений.

Я всегда пишу свой код, чтобы он не генерировал никаких предупреждений или ошибок, и очищаю его до тех пор, пока он не скомпилируется, не создавая посторонних шумов. Мусор, с которым мне приходится работать, ужасает меня, и я поражаюсь, когда мне приходится строить большой проект и наблюдать за потоком предупреждений, когда компиляция должна только сообщать, какие файлы она обработала.

Я также документирую свой код, потому что я знаю, что реальные затраты на программное обеспечение в течение всей жизни в основном связаны с его обслуживанием, а не с первоначальной записью, но это другая история ...


Не стесняйтесь, у консультантов есть хорошие деньги для людей, которые могут вслух читать клиентам предупреждения компилятора.
19

Код из других источников, генерирующих предупреждения, не обязательно означает, что авторы были небрежными. Это также может означать, что они скомпилировали код с другим компилятором, который генерировал другой набор предупреждений. Код может компилироваться без предупреждений на одном компиляторе и генерировать предупреждения на другом. Или, может быть, это просто другой набор параметров предупреждения; например, они использовали, -Wallи вы используете -Wall -Wextra.
celtschk

2

Некоторое предупреждение может означать возможную семантическую ошибку в коде или возможный UB. Например, ;после if(), неиспользуемая переменная, глобальная переменная, маскируемая локальным, или сравнение со знаком и без знака. Многие предупреждения связаны со статическим анализатором кода в компиляторе или с нарушениями стандарта ISO, обнаруживаемыми во время компиляции, которые «требуют диагностики». Хотя эти случаи могут быть законными в одном конкретном случае, в большинстве случаев они будут результатом проблем проектирования.

Некоторые компиляторы, например, gcc, имеют опцию командной строки для активации режима «предупреждения как ошибки», это хороший, хотя и жестокий инструмент для обучения начинающих программистов.


1

Тот факт, что компиляторы C ++ принимают код компиляции, который, очевидно, приводит к неопределенному поведению вообще является основным недостатком в составителей. Причина, по которой они этого не исправляют, заключается в том, что это может привести к поломке некоторых полезных сборок.

Большинство предупреждений должны быть фатальными ошибками, которые мешают завершению сборки. По умолчанию просто отображать ошибки и выполнять сборку в любом случае неправильно, и если вы не переопределите их для обработки предупреждений как ошибок и оставите некоторые предупреждения, то вы, скорее всего, в конечном итоге столкнетесь с аварийным завершением программы и выполнением случайных действий.


По иронии судьбы, много неопределенного поведения на самом деле не вызывает предупреждений, но тихо компилируется просто в противную бомбу замедленного действия. ; P
Джастин Тайм - Восстановить Монику

1
Проблема заключается в том, что если стандарт требует сообщения об ошибке, это сообщение об ошибке должно быть выдано во всех случаях, когда проблема возникает, но никогда, если проблема не возникает. Но в таких случаях, как неопределенное поведение, это может быть невозможно решить. Например, рассмотрим следующий код: int i; if (fun1()) i=2; if (fun2()) i=3; char s="abcde"[i];Этот код экспонатов неопределенное поведение , если и только если оба fun1()и fun2()может вернуться falseна то же выполнения функции. Что может или не может быть правдой, но как сказать компилятору?
celtschk

-2

Вы должны обязательно включить предупреждения компилятора, так как некоторые компиляторы плохо сообщают о некоторых распространенных ошибках программирования, включая следующие: -

-> инициализация переменной будет забыта -> вернуть значение из функции пропущено -> простые аргументы в семействах printf и scanf, не соответствующие строке формата, которую функция использует без предварительного объявления, хотя это происходит только в c

Так как эти функции могут быть обнаружены и сообщены, просто обычно не по умолчанию; поэтому эту функцию необходимо явно запрашивать с помощью параметров компилятора.


-32

Полегче: вам не нужно, это не нужно. -Wall и -Werror были разработаны маньяками-рефакторингами кода для себя: они были изобретены разработчиками компилятора, чтобы избежать разрушения существующих сборок после обновления компилятора на стороне пользователя . Особенностью является ничто, но все о решении сломать или не сломать сборку.

Это полностью зависит от вашего предпочтения, использовать его или нет. Я использую это все время, потому что это помогает мне исправить мои ошибки.


19
Хотя это не обязательно , настоятельно рекомендуется использовать их
Spikatrix

18
-Wall and -Werror was designed by code-refactoring maniacs for themselves.[править]
МКЦ

22
Кажется, ты противоречишь себе. Если вы «используете его все время, потому что это помогает исправить [ваши] ошибки», разве не стоит учить новых программистов, чтобы они делали это везде с самого начала? Я не думаю , что этот вопрос спрашивает , действительно ли это возможно для компиляции без -Wallи -Werror, это просто с просьбой , если это хорошая идея. Который, из вашего последнего предложения, звучит так, как будто вы говорите, что это так.
scohe001

12
Когда вы получите больше опыта в обслуживании кода, написанного не вами, вернитесь к этому ответу.
Торбьерн Равн Андерсен

Это не полезный ответ. В вопросе ОП есть 4 знака вопроса. Сколько ответит этот ответ?
Андерс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.