Чому я завжди повинен включати попередження компілятора?


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
Ви також можете скористатися клангом -Weverything
pmg

9
Єдиний модифікатор, який я хочу додати, - це те, що деякі попередження можуть не бути корисними для вашої програми. (Я бачив попередження, що компілятор додав 2 байти прокладки між елементами в структурі. Додаток був для прототипування, тому трохи витрачена пам'ять нас не турбувала.) Трактуйте всі попередження як помилки, а потім відключіть попередження лише якщо ви знаєте, чому це попередження не допоможе вам.
Kyle A

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

15
@interfect Так, це сталося зі мною пару разів. Немає великого. Якщо ви вирішили створити непідтримуваний фрагмент програмного забезпечення за допомогою компілятора, з яким він ніколи не був протестований, то краще будьте готові самостійно зайнятися деяким обслуговуванням.
н. 'займенники' м.

94

C, як відомо, є досить низьким рівнем мови, як це стосується HLL. C ++, хоча це може здатися значно вищим рівнем мови, ніж C, все ж поділяє низку його рис. І однією з таких рис є те, що мови були розроблені програмістами, для програмістів - і, зокрема, програмістів, які знали, що роблять.

[Що стосується решти цієї відповіді, я збираюся зосередитись на C. Більшість того, що я скажу, також стосується C ++, хоча, можливо, не так сильно. Хоча, як чудово говорив Б'ярн Струструп, "C полегшує себе стріляти в ногу; C ++ робить це важче, але коли ви це робите, це відбиває всю ногу". ]

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

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

Але, звичайно, не всі програмісти дійсно знають, що роблять. І, зокрема, кожен програміст на C (незалежно від того, наскільки досвідчений) проходить фазу свого початкового програміста на C. І навіть досвідчені програмісти C можуть недбало і помилитися.

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

Так виходить, що, здебільшого, попередження - це гарна ідея. Навіть досвідчені програмісти дізналися (насправді це " особливо досвідчені програмісти навчилися"), що, в цілому, попередження мають більше користі, ніж шкоди. Кожен раз, коли ви робили щось не так навмисно, і попередження викликало неприємність, мабуть, принаймні десять разів ви щось випадково зробили не так, і попередження врятувало вас від подальших неприємностей. І більшість попереджень можна вимкнути або вирішити за ті кілька разів, коли ви дійсно хочете зробити «неправильну» справу.

(Класичний приклад такої «помилка» є тестом if(a = b)Великий частини часу, це помилка, тому більшість компіляторів цих днів попередять про це. -. Деякі навіть за замовчуванням Але якщо ви дійсно хотіли як правонаступник bдо aі випробуванню в результаті ви можете відключити попередження, ввівши if((a = b)).)

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

Тому просити компілятора ставитися до попереджень як до помилок - це невелика хитрість, яку ви можете зіграти на собі, щоб обійти цю людську підданість.

Особисто я не так наполегливо ставлюсь до попереджень, як до помилок. (Насправді, якщо я чесний, я можу сказати, що я практично ніколи не вмикаю цей варіант у своєму "особистому" програмуванні.) Але ви можете бути впевнені, що цей параметр увімкнено на роботі, де наш посібник зі стилів (який я писав) мандат його використання. І я б сказав - я підозрюю, що більшість професійних програмістів скажуть - що будь-який магазин, який не трактує попередження як помилки в C, поводиться безвідповідально, не дотримується загальноприйнятих найкращих галузевих практик.


9
"програмісти, які знали, що роблять" - LOL; є помилка "не справжній шотландець", якщо я коли-небудь бачив її :)
Dancrumb

3
@Dancrumb LOL назад atcha. Я ніколи не впевнений, що розумію помилковість Шотландії , але мені це подобається, тому це буде гарною вправою для мене. Я думаю, що програма тут виглядає так: "Жоден програміст на C ніколи не писатиме if(a = b), тому нам не потрібно попереджати про це". (Тоді хтось створює список 10 критичних помилок у 10 випущених продуктах, які є наслідком цієї конкретної помилки.) "Гаразд, жоден досвідчений програміст C ніколи цього не напише ..."
Стів Самміт

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

5
Справа в тому, що більшість досвідчених програмістів дозволяють отримувати більшість, якщо не всі попередження. Якщо вони хочуть використовувати щось на кшталт if (returnCodeFromFoo = foo(bar)), тоді вони додають коментар і вимикають попередження (так що, коли програміст з технічного обслуговування перегляне це через 4 роки, він / вона зрозуміє, що код навмисний. Це сказав, я працював з тим, хто в (на землі Microsoft C ++) наполягав на тому, що поєднання / Стіна з поводженням з попередженнями як помилками - це шлях. Ага, це не так (якщо ви не хочете вносити багато коментарів щодо придушення).
Flydog57,

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

39

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

C ++, будучи повною мовою Тюрінга, має безліч випадків, коли компілятор повинен просто довіряти тому, що ви знали, що робите. Однак є багато випадків, коли компілятор може зрозуміти, що ви, мабуть, не мали наміру писати те, що ви написали. Класичний приклад - це коди printf (), які не відповідають аргументам, або std :: рядки, передані printf (не те, що коли-небудь трапляється зі мною!). У цих випадках написаний вами код не є помилкою. Це дійсний вираз C ++ з коректною інтерпретацією для компілятора, на який потрібно діяти. Але компілятор має сильну думку, що ви просто не помітили те, що легко знайти сучасний компілятор. Це попередження. Вони є очевидними для компілятора, використовуючи всі суворі правила C ++, які є в його розпорядженні, і які ви могли не помітити.

Вимкнути попередження або ігнорувати їх - це як вибрати вибір ігнорувати безкоштовні поради у тих кваліфікованіших, ніж ви. Це урок huberis, який закінчується, коли ви летите занадто близько до сонця і крила тануть, або виникає помилка пошкодження пам’яті. Між двома, я прийму падіння з неба будь-якого дня!

"Трактуйте попередження як помилки" - це крайня версія цієї філософії. Ідея тут полягає в тому, щоб ви вирішили кожне попередження, яке вам дає компілятор - ви слухаєте кожну частину безкоштовних порад і дієте на неї. Чи буде це для вас хорошою моделлю для розвитку, залежить від команди та над тим, над яким продуктом ви працюєте. Це подвижницький підхід, який може мати монах. Для деяких це чудово працює. Для інших це не так.

У багатьох моїх програмах ми не трактуємо попередження як помилки. Це робимо тому, що ці конкретні програми потрібно компілювати на декількох платформах з кількома компіляторами різного віку. Іноді ми знаходимо, що насправді неможливо виправити попередження на одній стороні, не перетворившись на попередження на іншій платформі. Тож ми просто обережні. Ми поважаємо попередження, але не перегинаємо їх назад.


11
Що стосується C ++, який є Тьюрінгом повним, це стосується. Дуже багато мов є вичерпними і не вірять вам, якщо ви робите щось не так ....
Прощайте, SE

3
@KamiKaze кожна мова матиме ідіоматичні помилки (наприклад, Java не може перешкодити вам писати непослідовну equals/ hashCode), і це питання якості впровадження, про які з них повідомляється.
Калет

2
@KamiKaze Біт повноти Тьюрінга вказує, що є випадки, коли компілятор не може довести, що ваш код не спрацює, як було заплановано. Це важливо, тому що компілятори не можуть зробити "неправильний" код помилкою. Помилки можуть бути зарезервовані лише для поведінки, для якої мовні дизайнери впевнені, що завжди буде "неправильним". (як правило, тому, що вона веде вниз шляхом, які є непослідовними).
Корт Аммон

2
Що також вказує на виклик із "усі попередження - це помилки". Задуми, за задумом, більш опортуністичні, що частіше запускають якийсь потенційно правильний код в обмін на запуск помилкового коду. Попередження як помилки призводить до того, що ви не зможете реалізувати всі можливості мови.
Корт Аммон

2
Однак загалом програмісти хочуть мови, яка робить більше, ніж "безпечну" річ. Ми хочемо, щоб мова робила те, що ми думали, що ми їй сказали. Таким чином, попередження залишаються важливими, оскільки власне клас речей, який ми хочемо зробити, це комп'ютер - це семантичний клас. Компілятор може вирішити це, визначивши "неправильне" або "небезпечне", але врешті-решт у вас є суперклас поведінки, який програміст хотів виконати. Попередження допомагають звузити цей суперклас.
Корт Аммон

19

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

Використовуйте правильний тип, поверніть це значення, оцініть це повернене значення. Знайдіть час і поміркуйте: "Чи справді це правильний тип у цьому контексті?" "Чи потрібно мені це повернути?" І біггі; "Чи буде цей код переносним протягом наступних 10 років?"

Увійдіть у звичку писати в першу чергу код без попередження.


17

Інші відповіді чудові, і я не хочу повторювати те, що вони сказали.

Ще один аспект "чому вмикати попередження", який не був належним чином торкнувся, - це те, що вони дуже допомагають у підтримці коду. Коли ви пишете програму значних розмірів, неможливо одразу тримати всю річ у голові. У вас зазвичай є функція або три, про які ви активно пишете і думаєте, і, можливо, файл або три на вашому екрані, на який ви можете посилатися, але основна частина програми існує десь у фоновому режимі, і ви повинні вірити, що це продовжує працювати.

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

Візьмемо для прикладу попередження про стукіт -Wswitch-enum. Це викликає попередження, якщо ви використовуєте перемикач на enum і пропускаєте одне з можливих значень enum. Ви можете подумати, що це було б малоймовірною помилкою: ви, мабуть, принаймні придивились до переліку значень перерахунків, коли ви писали заяву перемикача. Можливо, у вас навіть є IDE, який створив для вас параметри комутації, не залишаючи місця для людських помилок.

Це попередження дійсно стає власним, коли через півроку ви додасте ще один можливий запис до перерахунків. Знову ж таки, якщо ви думаєте про код, про який йдеться, ви, мабуть, будете добре. Але якщо цей перелік використовується для декількох різних цілей, і це одна з тих, кому потрібна додаткова опція, дуже просто забути оновити комутатор у файлі, якого ви не торкалися протягом 6 місяців.

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


9
Інший спосіб, коли вони допомагають у обслуговуванні, - це коли ви дивитесь на чужий код і не можете сказати, чи був побічний ефект навмисним. Із попередженнями ви знаєте, що вони принаймні були в курсі цього питання.
Робін Беннетт

Або в моєму випадку ви імпортуєте файл із вбудованої системи, яка містить оператор перемикання рядків 3000+ над enum з кількома тисячами значень. Попередження "пропадає" (уникнути використання goto) маскували ряд помилок "без обробки" ... вбудований компілятор не випускав жодної з цих, але помилки були важливі.
Móż

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]);
      |                     ^

який я міг ігнорувати і виконувати код у будь-якому випадку .. І тоді я став свідком "великої" помилки сегментації, як говорив мій професор епікуру ІР:

Помилка сегментації

Щоб налагодити це в реальному сценарії, слід почати з лінії, яка викликає помилку сегментації, і спробувати простежити, що є коренем причини. Їм доведеться шукати, що трапилося з цією колосальною сумою iі strвсередині неї. коду там ...

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

Якби вони не ігнорували попередження, вони знайшли б помилку негайно!


4
До назви: не обов’язково. Наприклад, попередження, що пропонує використовувати дужки у формулі, яка їм справді не потрібна, вказує на непроблему, яка ніколи не спричинить помилку. Пріоритети оператора в даній мові програмування не змінюються. Колись.
Марк ван Левен

4
@MarcvanLeeuwen Екземпляр, який ви цитуєте, може перетворитись на помилку, наприклад, якщо програміст, який не пам'ятає пріоритет оператора, правильно модифікує формулу. Попередження говорить вам: "комусь в якийсь момент може бути незрозуміло, додайте круглі дужки, щоб зробити це більш зрозумілим". Хоча треба погодитися, що назва оригіналу публікації не завжди відповідає дійсності.
Hubert Jasieniecki

^ Що-небудь може перетворитись на помилку. Так само легко ввести помилку в частково скоплений код, як і в повністю скоплений код.
Джим Балтер

... Убік у мене є питання до налагоджувача, перша реакція якого на "О, це відійшло від str[idx]" не "Добре, де strі idxвизначено?"
Джастін Час -

2
Вам пощастило, якщо ви отримаєте помилку в сегментації. Якщо вам пощастило менше, то, можливо, випадково idxви отримаєте значення, яке ви очікували на своєму тесті (не надто малоймовірно, якщо очікуване значення дорівнює 0), і насправді трапляються вказівки на деякі конфіденційні дані, які ніколи не слід друкувати при розгортанні.
celtschk

14

Трактувати попередження як помилки - це лише засіб самодисципліни: ви складали програму для перевірки цієї блискучої нової функції, але ви не можете, поки не виправите неохайні частини. Додаткової інформації немає Werror, вона просто чітко визначає пріоритети:

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

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

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

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


3
На краще або на гірше, clippyпідшивальний інструмент для Іржі насправді попереджатиме про постійну "3,14". Це насправді приклад у документах . Але, як ви могли здогадатися з назви, clippyпишається тим, що агресивно допомагає.
ЕМК

1
@emk Спасибі за цей приклад, можливо, я повинен перефразувати свою відповідь таким чином, як ніколи не говорити "ніколи" . Я не хотів сказати, що перевірити точність π значень неможливо, лише те, що позбутися попереджень не гарантує гідної якості коду.
Дмитро Григор'єв

Одне з попереджень про помилки - це те, що автоматичні збірки вийдуть з ладу, тим самим попереджаючи про те, що щось пішло не так. Автоматизовані конструкції також дозволяють автоматизувати прокладку (вибух 3 ... 2 ... 1 .. :)
Móż

8

Оскільки хтось, хто працює зі застарілим вбудованим кодом C, включення попереджень компілятора допомогло показати багато слабких місць та областей для пошуку, коли пропонується виправлення. У ПКУ використання -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-змінної]

-Wextra також скаже вам, що ваш параметр b нічого не робить:

foo.c: У функції 'foo':

foo.c: 9: 20: попередження: невикористана змінна 'c' [-Wunused-змінної]

foo.c: 7: 20: попередження: невикористаний параметр 'b' [-Wunused-parameter] 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" затінює глобальну декларацію [-Світ]

foo.c: 1: 5: Примітка: тіньова декларація тут

Форматування рядків

Для цього не потрібні додаткові прапорці в 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 / ones / pop для коду, який розробник був впевнений, що це справді добре, а також протокол журналу на рівні налагодження, про всяк випадок.

Ця практика добре працювала у нас.


1
Відряджений. #pragma warningне просто придушує попередження, він служить подвійним цілям швидкого повідомлення іншим програмістам про те, що щось є навмисним, а не випадковим, і виступає як тег пошуку для швидкого пошуку потенційно проблемних областей, коли щось ламається, але виправлення помилок / попереджень не робить полагодьте це.
Час Джастіна -

Ви маєте рацію Джастін, саме так я переглядав попередження #pragma
Jim In Texas

3

Попередження - це помилка, яка чекає, що станеться. Таким чином, ви повинні увімкнути попередження компілятора та налагодити свій код, щоб видалити будь-яке попередження.


3

Є лише одна проблема з поводженням з попередженнями як помилками: коли ви використовуєте код, що надходить з інших джерел (наприклад, бібліотеки мікро $ ** t, проекти з відкритим кодом), вони не виконали свою роботу правильно, а компілюючи їх код, створюється тон попереджень

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

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


Не стукайте, є хороші гроші на консультаційну роботу для людей, які можуть читати попередження компілятора вголос для клієнтів.
Móż

Код з інших джерел генерації сигналів тривоги необхідні означає , що автори були охайні. Це також може означати, що вони склали код з іншим компілятором, який генерував різний набір попереджень. Код можна компілювати без попереджень на одному компіляторі, а генерувати попередження на іншому. А може, це просто інший набір попереджувальних варіантів; наприклад, вони використовували -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.[цитування потрібно]
YSC

22
Схоже, ти собі суперечить. Якщо ви "користуєтесь цим постійно, оскільки це допомагає виправити [ваші] помилки", чи не варто навчати новіших програмістів, щоб вони робили це скрізь з початку? Я не думаю , що це питання запитує , чи дійсно це можливо для компіляції без -Wallі -Werror, це просто з проханням , якщо це гарна ідея. Що з вашого останнього речення звучить так, як ви говорите.
scohe001

12
Коли ви отримаєте більше досвіду з підтримкою написаного вами коду, перегляньте цю відповідь.
Thorbjørn Ravn Andersen

Це не корисна відповідь. У питанні щодо ОП є 4 знаки запитання. На скільки відповідає ця відповідь?
Андерс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.