Прапори, щоб увімкнути ретельне та багатослівне попередження g ++


122

Часто в C under 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++? (Я знаю, що багато з них будуть однаковими.)


69
Які потреби GCC (так як він вирішив нахабно брехня про -Wall) є -Wbloody_everythingпрапор :-)
paxdiablo

Ви можете відзначити своє запитання дурпом, але ви можете також поставити останню редагування як відповідь, оскільки ви насправді відповіли на своє запитання. І я був би радий підняти це тоді :)
ere

4
OP і @paxdiablo: GCC постійно відкидає подібні речі, але це доступно в Clang через -Weverything. Я читав, що навіть розробники Clang ++ трохи стурбовані тим, що користувачі вмикають його; мабуть, він призначався лише для внутрішнього розвитку. Це не має сенсу, оскільки ввімкнення -Weverything- це, мабуть, найкращий спосіб виявити потенційно корисні попередження, про які ви раніше не знали.
Кайл Странд

1
OP і @paxdiablo Зараз існує спосіб розібратися з повним списком попереджень для даної версії GCC: github.com/barro/compiler-warnings
Kyle Strand

Відповіді:


138

Я пройшов і знайшов мінімальний набір включень, який повинен отримати максимальний рівень попередження. Потім я вилучив із цього списку набір попереджень, які, на мою думку, насправді не вказують на те, що відбувається щось погане, або в іншому випадку є занадто багато помилкових позитивних даних, щоб їх можна було використовувати в реальній збірці. Я коментував, чому кожен із тих, кого я виключав, був виключений. Це мій останній набір запропонованих попереджень:

-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). Прикладом мого коду, де я це використовую, є те, що у мене є вектор float. Я переглядаю цей вектор, і є деякі елементи, які я ще не можу оцінити, якими вони повинні бути, тому я встановив їх до -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), щоб переконатися, що ви реально покрили всі можливі варіанти. Це дозволяє вам бути ясним у тому, що стосується вашої проблеми, і програмно виконує це. Однак вам доведеться бути обережними, просто скрізь дотримуючись твердження (помилкового). Це краще, ніж робити нічого у випадку за замовчуванням, але, як зазвичай, у арсеналі, він не буде працювати у версії версій. Іншими словами, ви не можете розраховувати на те, щоб перевірити номери, які ви отримаєте, скажімо, від мережевого з'єднання або бази даних, над якими не маєте абсолютного контролю. Винятки або повернення рано - найкращий спосіб вирішити це (але все-таки вимагати, щоб у вас був випадок за замовчуванням!).

  • -Werrorє для мене важливим. Складаючи велику кількість коду в багатопотоковій збірці з кількома цілями, попередження легко пропустити. Перетворення попереджень у помилки гарантує, що я їх помічаю.

Тоді є набір попереджень, які не включені до переліченого списку, тому що я не вважаю їх корисними. Це застереження та мої коментарі, чому я не включаю їх до списку за замовчуванням:

Попередження відсутні:

  • -Wabiне потрібен, оскільки я не поєдную бінарні файли від різних компіляторів. Я намагався компілювати його все одно, і це не спрацьовує, тому це не здається багатослівним.

  • -Waggregate-returnя не вважаю помилкою. Наприклад, він спрацьовує при використанні циклу на основі діапазону на векторі класів. Оптимізація зворотної вартості повинна враховувати будь-які негативні наслідки цього.

  • -Wconversionзапускає цей код: short n = 0; n += 2;Неявна конверсія в int викликає попередження, коли потім перетворюється назад у цільовий тип.

  • -Weffc++включає попередження, якщо всі учасники даних не ініціалізовані у списку ініціалізатора. Я навмисно цього не роблю у багатьох випадках, тому набір попереджень занадто захаращений, щоб бути корисним. Корисно вмикати кожен раз і перевіряти інші попередження (наприклад, невіртуальні деструктори базових класів). Це було б корисніше як збірка попереджень (наприклад -Wall), а не окреме попередження самостійно.

  • -Winlineвідсутня, оскільки я не використовую вбудоване ключове слово для оптимізації, просто для визначення функцій, вбудованих у заголовки. Мені байдуже, чи оптимізатор насправді накреслює це. Це попередження також скаржиться, якщо воно не може вбудувати функцію, оголошену в тілі класу (наприклад, порожній віртуальний деструктор).

  • -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увімкнено періодично, щоб оптимізувати компонування класів, але це не залишається увімкненим, оскільки не у всіх класах є достатньо елементів для видалення прокладки в кінці. Теоретично я міг отримати кілька додаткових змінних для "free", але не варто витрачати додаткових зусиль на підтримку цього (якщо розмір мого класу зміниться, видалити ці раніше вільні змінні непросто).

  • -Wstack-protector не використовується, тому що я не використовую -fstack-protector

  • -Wstrict-aliasing=3увімкнено -Wallі є найбільш точним, але схоже, що рівень 1 і 2 дають більше попереджень. Теоретично нижчий рівень є "сильнішим" попередженням, але це ціною більше помилкових позитивних результатів. Мій власний тестовий код складено чисто під усі 3 рівні.

  • -Wswitch-enumне поведінка, яку я хочу. Я не хочу чітко обробляти кожну операцію перемикання. Було б корисно, якби в мові був якийсь механізм активувати це у визначених операторах переключення (щоб гарантувати, що майбутні зміни до перерахунку обробляються скрізь, де вони повинні бути), але це буде надмірним для налаштування "все-чи-нічого".

  • -Wunsafe-loop-optimizationsвикликає занадто багато помилкових попереджень. Може бути корисним застосовувати це періодично і вручну перевіряти результати. Як приклад, він створив це попередження у своєму коді, коли я перекинув усі елементи у векторі, щоб застосувати до них набір функцій (використовуючи діапазон для циклу). Це також попереджає для конструктора масиву const const std :: string (де це не цикл у коді користувача).

  • -Wzero-as-null-pointer-constantі -Wuseless-castє попередженнями лише для GCC-4.7, які я додам під час переходу до GCC 4.7.

Я подав кілька звітів про помилки / запити на покращення в gcc в результаті деяких досліджень, тому, сподіваюся, я зможу врешті додати більше попереджень із списку "не включати" до списку "включити" . Цей список включає всі попередження, згадані в цій темі (плюс, я думаю, кілька додаткових). Багато попереджень, про які явно не згадується у цій публікації, включені як частина іншого попередження, яке я згадую. Якщо хтось помітить будь-які попередження, які повністю виключені з цієї публікації, дайте мені знати.

редагувати: Схоже, я пропустив декілька (які я зараз додав). На сторінці http://gcc.gnu.org насправді є друга сторінка, яка досить добре прихована. Загальні параметри попередження та параметри C ++ (прокручуйте униз донизу, щоб отримати попередження)


Нещодавно я надіслав запит на вдосконалення на основі моїх досліджень на цю відповідь: gcc.gnu.org/bugzilla/show_bug.cgi?id=53313 . Це значно спростило б попереджувальну ситуацію, створивши рівні попередження. У моїй пропозиції мій запропонований набір попереджень становить приблизно -W4, з додатковою пропозицією створити -Winf, що означало б "Все - і" я - справді означаю - це - цей час
Девід Стоун

Запит на покращення, який спричинив би частину -Wpadded, буде доданий до рекомендованого списку: gcc.gnu.org/bugzilla/show_bug.cgi?id=53514
Девід Стоун

Запит на покращення, який призведе до того, що частини -Weffc ++ будуть додані до рекомендованого списку: gcc.gnu.org/bugzilla/show_bug.cgi?id=16166
Девід Стоун

1
@Predelnik: Це складніше, ніж це. -Wswitch-enumпопереджає, якщо ви не обробляєте явно кожне значення перерахунку в комутаторі і defaultне вважається явним. З іншого боку, -Wswitch-defaultпопереджає вас, якщо у вашого комутатора немає defaultсправи, навіть якщо ви явно покрили всі можливі значення.
Девід Стоун

2
BTW - використовуйте -isystemзамість -Iсвого "старого коду бібліотеки", щоб запобігти всім помилковим
справам

39

О, усі мої оригінальні пошукові запити на 99% повідомлень про те, як придушити попередження (досить страшно), але я просто наткнувся на цей коментар , у якому є цей чудовий набір прапорів (деякі менш релевантні):

Хрест перевіряється:

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

-g -O -Wall -Weffc++ -pedantic  \
-pedantic-errors -Wextra -Waggregate-return -Wcast-align \
-Wcast-qual -Wconversion \
-Wdisabled-optimization \
-Werror -Wfloat-equal -Wformat=2 \
-Wformat-nonliteral -Wformat-security  \
-Wformat-y2k \
-Wimplicit  -Wimport  -Winit-self  -Winline \
-Winvalid-pch   \
-Wlong-long \
-Wmissing-field-initializers -Wmissing-format-attribute   \
-Wmissing-include-dirs -Wmissing-noreturn \
-Wpacked  -Wpadded -Wpointer-arith \
-Wredundant-decls \
-Wshadow -Wstack-protector \
-Wstrict-aliasing=2 -Wswitch-default \
-Wswitch-enum \
-Wunreachable-code -Wunused \
-Wunused-parameter \
-Wvariadic-macros \
-Wwrite-strings

Отже, я думаю, що це хороший вихідний пункт. Не усвідомлював, що це дуп, але, принаймні, він був глибоко похований. :-)


1
Можливо, але це, здається, змінюється між версіями, і, швидше за все, примхами сонячних плям та RMS, тому надмірно явна вірогідність не зашкодить. Це все-таки хороша відправна точка.
Sdaz MacSkibbons

3
Із швидкого звільнення c-opts.c / opts.c 4.5.2 для 'case OPT_W', вам не вистачає: суворий переповнення, undef, сувора нульова дозорна, нормалізована, мультичарова, неявна функція декларування, застаріла, мітки endif, коментар s , вбудований макрос переосмислений, більший за, більший за eq, abi Божевільно, що для переліку їх не існує варіанти командного рядка.
Тоні Делрой

3
Я думаю, що це божевільніше те, -Wallщо не робить того, чого можна було б очікувати. Але дякую, деякі з них виглядають дуже корисно!
Sdaz MacSkibbons

1
Вимкнення попереджень має своє місце. Адже вони є "попередженнями". Інша ситуація, коли ви вмикаєте прапор, який дозволяє кілька попереджень, але ви хочете бути виборчими щодо нього.
Tamás Szelei

1
Як ти вмієш користуватися -Waggregate-return? Це дає мені попередження про кожне використанняbegin/end()
Flamefire

13

Деякі з них уже включені до -Wallабо -Wextra.

Гарною базовою установкою для C є:

-std=c99 -pedantic -Wall -Wextra -Wwrite-strings -Werror

а для C ++

-ansi -pedantic -Wall -Wextra -Weffc++

(пропуск -Werrorна C ++, оскільки -Weffc++має деякі роздратування)


10
-Werror можна відключити для конкретних типів попереджень, наприклад: -Werror -Weffc ++ -Wno-error = effc ++
Роберт Хенсінг

2
ansi : У режимі C це еквівалентно -std=c89. У режимі C ++ він еквівалентний -std=c++98. тобто якщо ви вказуєте якусь іншу std, не використовуйтеansi
Шон Брекенрідж

2

Спробуйте

export CFLAGS="`gcc --help=warnings | grep '\-W' | awk '{print $1 \" \"}' |
sort | uniq` -pedantic -fdiagnostics-show-option -Werror"

Це швидкий і брудний старт, який, безумовно, потребує налаштування; з одного боку, навіть якщо ви зателефонуєте компілятору відповідною назвою для вашої мови (наприклад, g++для C ++), ви отримаєте попередження, які не застосовуються до цієї мови (і компілятор кине руки і відмовиться продовжувати, поки ви не зняти попередження).

Інша справа, що я додав -Werror, тому що якщо ви не виправляєте попередження, чому ви дбаєте про їх включення? Ви також можете зняти попередження зі списку. (Наприклад, я майже ніколи не використовую -Waggregate-returnC ++.)

Деякі попередження нічого не зроблять без інших параметрів, пов’язаних із продуктивністю ( -Wstack-protector). -fdiagnostics-show-optionі керівництво GCC - ваші друзі.

До речі, деякі попередження є взаємовиключними; зокрема використання -Wtraditionalта -Wold-style-definitionпоряд із цим -Werrorне збираються.


0

У CmakeLists.txt мого Кліона

cmake_minimum_required(VERSION 3.13)
project(cpp17)

set(CMAKE_CXX_STANDARD 17)

set(GCC_COVERAGE_COMPILE_FLAGS "-std=c++17 -Wall -Weffc++ -Wno-error=effc++ -pedantic \
 -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-newline-eof  \
-pedantic-errors -Wextra -Waggregate-return -Wcast-align \
-Wcast-qual -Wconversion \
-Wdisabled-optimization \
-Werror -Wfloat-equal -Wformat=2 \
-Wformat-nonliteral -Wformat-security  \
-Wformat-y2k \
-Wimplicit  -Wimport  -Winit-self  -Winline -Winvalid-pch   \
-Wlong-long \
-Wmissing-field-initializers -Wmissing-format-attribute   \
-Wmissing-include-dirs -Wmissing-noreturn \
-Wpacked  -Wpadded -Wpointer-arith \
-Wredundant-decls \
-Wshadow -Wstack-protector \
-Wstrict-aliasing=2 -Wswitch-default \
-Wswitch-enum \
-Wunreachable-code -Wunused \
-Wunused-parameter \
-Wvariadic-macros \
-Wwrite-strings")


set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )

add_executable(cpp17 main.cpp)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.