У контексті я розробник Clang, який працює в Google. В Google ми продемонстрували діагностику Clang для (по суті) всіх наших розробників C ++, і ми також трактуємо попередження Clang як помилки. Як розробник Clang, так і один з найбільших користувачів діагностики Clang, я спробую пролити трохи світла на ці прапори і як їх можна використовувати. Зауважте, що все, що я описую, є загальноприйнятним для Clang, і не є специфічним для C, C ++ або Objective-C.
TL; DR версія: Будь ласка , використовуйте -Wall
і -Werror
, як мінімум , на будь-який новий код , який ви розробляєте. Ми (розробники компілятора) додаємо тут попередження з поважних причин: вони знаходять помилки. Якщо ви виявите застереження, що виловлює помилок для вас, увімкніть і його. Спробуйте -Wextra
тут купу хороших кандидатів. Якщо один із них занадто галасливий, щоб ви з користю користувалися, подайте помилку . Якщо ви пишете код, який містить "очевидну" помилку, але компілятор не попереджав про це, подайте помилку.
Тепер про довгу версію. Спочатку деякі відомості про групування попереджувальних прапорів. У Кланг (і в обмеженій мірі в GCC) існує багато "групувань" попереджень. Кілька релевантних для цієї дискусії:
- За замовчуванням: Ці попередження завжди активовані, якщо ви явно не відключите їх.
-Wall
: Це попередження про те, що розробники мають високу довіру як до їх вартості, так і до низької помилково-позитивної.
-Wextra
: Це попередження, які, як вважають, є цінними та здоровими (тобто вони не є помилками), але вони можуть мати високі помилково-позитивні оцінки або загальні філософські заперечення.
-Weverything
: Це божевільна група, яка буквально дає можливість будь-яке
попередження в Кланг. Не використовуйте це у своєму коді. Він призначений строго для розробників Clang або для вивчення того, які існують попередження .
Вище згадані два основні критерії, які направляють, куди надходять попередження в Кланг, і давайте уточнимо, що це насправді означає. Перший - потенційне
значення конкретного явища попередження. Це очікувана вигода для користувача (розробника), коли попередження спрацьовує та правильно
ідентифікує проблему з кодом.
Другий критерій - це ідея хибнопозитивних звітів. Це ситуації, коли попередження спрацьовує на коді, але потенційна проблема, що цитується, насправді не виникає через контекст чи інше обмеження програми. Код, про який попереджено, насправді поводиться правильно. Вони особливо погані, коли попередження ніколи не було спрямоване на цей код. Натомість саме дефіцит у виконанні попередження викликає його загоряння.
Для попереджень Кланг значення повинно бути з точки зору правильності , а не з точки зору стилю, смаку чи умовності кодування. Це обмежує набір наявних попереджень, виключаючи часто запитувані попередження, такі як попередження, коли {}
s не використовується навколо тіла if
заяви. Кланг також дуже нетерпимий до хибнопозитивних . На відміну від більшості інших компіляторів, він використовуватиме неймовірну різноманітність джерел інформації для обрізки помилкових позитивних результатів, включаючи точне написання конструкції, наявність або відсутність зайвих '()', кастів або навіть препроцесорних макросів!
Тепер давайте візьмемо кілька реальних прикладів попереджень від 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.
Тут не потрібен прапор, щоб отримати це попередження. Обґрунтування полягає в тому, що це код ніколи не є правильним, надаючи попередження високе значення , і попередження спрацьовує лише за кодом, який може довести Клэнг, потрапляє в це відро, даючи йому нульову помилкову швидкість.
% 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
прапор. Причина полягає в тому, що існує дуже
велика база кодів, де невідповідний знак для порівнянь надзвичайно поширений. Хоча це попередження виявляє деякі помилки, ймовірність того, що код є помилкою, коли користувач пише, що він в середньому досить низький. Результат - надзвичайно висока помилково-позитивна норма. Однак, коли в програмі є помилка через дивні правила просування, часто це надзвичайно тонко робить таке попередження,
коли прапорці помилки мають відносно високе значення . Як наслідок, Кланг надає це та виставляє його під прапором.
Зазвичай попередження не існують довго поза -Wextra
прапором. Кланг дуже намагається не застосовувати попередження, які не бачать регулярного використання та тестування. Додаткові попередження, -Weverything
включені зазвичай, є попередженнями під час активного розвитку або з активними помилками. Або вони будуть закріплені та розміщені під відповідними прапорами, або їх слід зняти.
Тепер, коли ми зрозуміли, як ці речі працюють з Кланг, давайте спробуємо повернутися до початкового питання: які застереження слід увімкнути для розвитку? Відповідь, на жаль, залежить від цього. Розгляньте наступні питання, які допоможуть визначити, які застереження найкраще підходять для вашої ситуації.
- Чи маєте ви контроль над усім своїм кодом, чи частина його зовнішня?
- Які ваші цілі? Ловити помилки чи писати кращий код?
- Яка ваша хибнопозитивна толерантність? Чи готові ви регулярно писати додатковий код, щоб замовчувати попередження?
По-перше, якщо ви не контролюєте код, не намагайтеся ввімкнути додаткові попередження. Будьте готові відключити. У світі багато поганого коду, і ви, можливо, не зможете все це виправити. Що це нормально. Працюйте, щоб знайти спосіб зосередити свої зусилля на контрольованому вами коді .
Далі з’ясуйте, що ви хочете від своїх попереджень. Це різне для різних людей. Clang намагатиметься попередити без будь-яких варіантів нападкових помилок або моделей коду, для яких у нас є давній історичний прецедент, який свідчить про надзвичайно високий рівень помилок. Вмикаючи, -Wall
ви збираєтеся отримати набагато більш агресивний набір попереджень, спрямованих на пошук найпоширеніших помилок, які спостерігали розробники Clang у коді C ++. Але в обох випадках
помилково-позитивний показник повинен залишатися досить низьким.
Нарешті, якщо ви абсолютно готові замовкнути * хибнопозитивні * s на кожному кроці, продовжуйте -Wextra
. Файлові помилки, якщо ви помітили попередження, які вловлюють багато справжніх помилок, але які мають нерозумні чи безглузді помилкові позитиви. Ми постійно працюємо , щоб знайти способи , щоб принести більше і більше помилок ознайомчої логіки уявити в -Wextra
в -Wall
де ми можемо уникнути помилкових спрацьовувань.
Багато хто виявить, що жоден із цих варіантів для них не є правильним. У Google ми -Wall
відключили деякі попередження через багато існуючого коду, який порушив попередження. Ми також включили деякі попередження прямо, хоча вони не ввімкнуті -Wall
, оскільки вони мають для нас особливо високе значення. Пробіг варіюватиметься, але, ймовірно, змінюватиметься аналогічно. Часто може бути набагато краще включити кілька ключових попереджень, а не всі
-Wextra
.
Я б закликав усіх увімкнути -Wall
будь-який не спадковий код. Щодо нового коду, попередження тут майже завжди цінні та дійсно покращують досвід розробки коду. І навпаки, я б закликав усіх
не допускати прапорів за межами -Wextra
. Якщо ви знайшли попередження Clang , який -Wextra
не включає в себе , але який виявляється зовсім цінним для вас, просто файл помилки , і ми , ймовірно , можемо поставити його під -Wextra
. Від того, чи явно ви ввімкнете деякий підмножина попереджень у, -Wextra
буде сильно залежати від вашого коду, вашого стилю кодування та того, чи підтримувати цей список простіше, ніж виправити все, що не виявлено -Wextra
.
З переліку попереджень ОП (які включають обидва -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. Чи попередить Кланг про їх використання, залежить від поширеності розширення. Кланг прагне до сумісності з GCC, і тому у багатьох випадках це полегшує ситуацію з неявними розширеннями мови, які широко використовуються. -Wwrite-strings
, як коментує ОП, це прапор сумісності від 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 і надає деяку інформацію для тих, хто намагається вибрати набір попереджень для їх використання або використання їхньої компанії.