Корисні прапорці GCC для C


157

Крім налаштування -Wallта налаштування -std=XXX, які інші справді корисні, але менш відомі прапорці компілятора існують для використання в C?

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


9
Ну -save-temps, -Wshadowі -fmudflapбули найбільшими знахідками, про які я не знав, завдяки усім.
Метт Столяр

Контекст, наскільки я можу сказати: запуск gcc -c [flags-go-here] -o myprog.o myprog.cдля компіляції (не посилання) програми C.
Rory O'Kane

Відповіді:


64

-fЦікаво кілька варіантів генерації коду:

  • -ftrapvФункція змусить програму , щоб перервати на підписаному целочисленное переповнення (формально «невизначене поведінку» в C).

  • -fverbose-asmкорисно, якщо ви збираєтесь -Sвивчити результати складання - це додає деякі інформативні коментарі.

  • -finstrument-functions додає код для виклику функцій профілювання, що надаються користувачем, у кожній точці входу та виходу функції.


Бо -ftrapv, загляньте сюди stackoverflow.com/questions/20851061/… .., схоже, є помилка, яка довго чекає виправлення.
Арджун Средхаран

Чи можете ви перевірити коментар вище?
Сурай Джайн

-ftrapv по суті замінено -fsanitize = підписано-ціле число-переповнення.
Марк Глісс

139

Ось мої:

  • -Wextra, -Wall: істотне.
  • -Wfloat-equal: корисно, оскільки зазвичай тестування чисел з плаваючою комою на рівність погано.
  • -Wundef: попередити, якщо неініціалізований ідентифікатор оцінюється в #ifдирективі.
  • -Wshadow: попереджайте, коли локальна змінна затінює іншу локальну змінну, параметр або глобальну змінну або коли тінь, що вбудовується, є тіньовою.
  • -Wpointer-arith: попередити, якщо щось залежить від розміру функції або від void.
  • -Wcast-align: попереджайте кожного разу, коли вказується покажчик, щоб збільшити необхідне вирівнювання цілі. Наприклад, попередити, якщо a char *призначається int *на машинах, де цілі числа можуть бути доступні лише у дво- або чотирьохбайтових межах.
  • -Wstrict-prototypes: попередити, якщо функція оголошена або визначена, не вказуючи типи аргументів.
  • -Wstrict-overflow=5: попереджає про випадки, коли компілятор оптимізує виходячи з припущення, що переповнення підпису не відбувається. (Значення 5 може бути занадто суворим, див. Сторінку керівництва.)
  • -Wwrite-strings: дайте рядкові константи const char[довжини типу, ]щоб скопіювати адресу одного в не const char *вказівник отримає попередження.
  • -Waggregate-return: попереджає, чи визначені чи викликані функції, що повертають структури чи об'єднання.
  • -Wcast-qual: попереджайте щоразу, коли вказується покажчик, щоб видалити класифікатор типу з цільового типу * .
  • -Wswitch-default: попереджайте, коли у switchзаяві немає defaultвипадку * .
  • -Wswitch-enum: попереджайте, коли у switchоператорі є індекс переліченого типу і не вистачає а caseдля одного або декількох названих кодів цього перерахунку * .
  • -Wconversion: попередити про неявні перетворення, які можуть змінити значення * .
  • -Wunreachable-code: попередити, якщо компілятор виявить, що код ніколи не буде виконаний * .

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


11
Досить повний список, просто хочеться додати ще один; -Wformat=2: Додаткові перевірки формату функцій printf / scanf.
знімок

1
хіба все це не мається на увазі -Wall?
чача15

2
@ chacham15, ні, я так не думаю. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal

1
@Alok хм, може, це не стандартне серед дистрибуцій? Я знаю, що на своєму mbp я мушу явно вимкнутись, -Wwrite-stringsтому що я його так ненавиджу.
чача15

@ chacham15, можливо. Але опис -Wwrite-stringsконкретно говорить, що це не частина -Wall: gcc.gnu.org/onlinedocs/gcc/… . Можливо, щось інше у ваших налаштуваннях встановлює цей прапор? А може, ви компілюєте C ++?
Алок Сінгал

52

Завжди використовуйте -Oабо вище ( -O1, -O2, -Osі т.д.). На рівні оптимізації за замовчуванням gcc іде на швидкість компіляції і не робить достатнього аналізу, щоб попереджати про такі речі, як неіціалізовані змінні.

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

-Wall в значній мірі вмикає попередження, які, ймовірно, є помилками.

Попередження, включені до, -Wextraяк правило, позначають загальний законний код Вони можуть бути корисними для огляду коду (хоча програми в стилі ворсинок знаходять набагато більше підводних каменів і більш гнучких), але я б не вмикав їх для нормальної розробки.

-Wfloat-equal це гарна ідея, якщо розробники проекту не знайомі з плаваючою точкою, і погана ідея, якщо вони є.

-Winit-selfкорисний; Цікаво, чому це не входить -Wuninitialized.

-Wpointer-arithкорисно, якщо у вас є переважно портативний код, який не працює -pedantic.


9
+1 для "-Wfloat-Equal" - це гарна ідея, якщо розробники проекту не знайомі з плаваючою точкою, і погана ідея, якщо вони є. " особливо друга її половина. :-)
R .. GitHub ЗАСТАНОВИТИ ДІЙ

39
-save-temps

Це залишає після себе результати препроцесора та збірки.

Попередньо оброблене джерело корисно для налагодження макросів.

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


Мені було цікаво, як ви це зробили ... Я завжди просто просив gcc скинути збірку, якщо мені це потрібно.

35

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


35

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

Ось демонстрація:

$ cat mf.c 
int main()
{
 int a[10];
 a[10]=1; // <-- o noes, line 4
}

$ gcc -fmudflap mf.c -lmudflap
$ ./a.out 
*******
mudflap violation 1 (check/write): time=1280862302.170759 ptr=0x7fff96eb3d00 size=44
pc=0x7f3a575503c1 location=`mf.c:4:2 (main)'
      /usr/lib/libmudflap.so.0(__mf_check+0x41) [0x7f3a575503c1]
      ./a.out(main+0x90) [0x400a54]
      /lib/libc.so.6(__libc_start_main+0xfd) [0x7f3a571e2c4d]
Nearby object 1: checked region begins 0B into and ends 4B after
mudflap object 0xf9c560: name=`mf.c:3:6 (main) a'
bounds=[0x7fff96eb3d00,0x7fff96eb3d27] size=40 area=stack check=0r/3w liveness=3
alloc time=1280862302.170749 pc=0x7f3a57550cb1
number of nearby objects: 1

Гммм, багрянина здається досить неприємною: P
Метт Столяр

9
-fmudflapбільше не підтримується, оскільки GCC 4.9 ви отримуєте warning: switch '-fmudflap' is no longer supported. Його замінив AddressSanitizer.
Агостіно

21

Не дуже пов’язаний із C / C ++, але корисний у будь-якому випадку:

@file

Покладіть всі вищезазначені хороші прапори (які ви всі вказали) у "файл", і використовуйте цей вище прапор, щоб використовувати всі прапори у цьому файлі разом.

наприклад:

Файл: compilerFlags

-Стінка

-std = c99

-Векстра

Потім компілюйте:

gcc yourSourceFile @compilerFlags

15

-march=native створити оптимізований код для платформи (= чіпа), на якій ви збираєтеся


2
Якщо ви збираєте для інших машин, де ви не знаєте цілі, ви можете використовувати mtune = xxx, який оптимізується без використання наборів інструкцій. Наприклад, mtune = generic постійно оновлюється з "середніми" процесорами випадку.
Turix

15

Якщо вам потрібно знати прапори препроцесора, які визначені компілятором:

echo | gcc -E -dM -

13

Це не дуже корисно для виявлення помилок, але рідко згадуваний -masm=intelваріант робить використання-S для перевірки результатів складання набагато, набагато приємніше.

Синтаксис збірки AT&T занадто сильно болить голову.


2
Для мене різниця між AT&T та Intel - це різниця між C # та Java. Просто синтаксис. Обидва жахливі. :)
Метт Столяр

2
+1 @michael для створення gcc використовує синтаксис intel замість бога жахливого в & t. Перевірка складання використовує достатню кількість мозкових циклів - не потрібно витрачати мозкові цикли, які src передує до призначення в опкодах. Тепер якщо тільки gcc підтримує вбудований __asm ​​{}, як і інші компілятори, ми все готові!
greatwolf

10

Мій makefile зазвичай містить

  CFLAGS= -Wall -Wextra -Weffc++ -Os -ggdb
  ...
  g++ $(CFLAGS) -o junk $<
  gcc $(CFLAGS) -o $@ $<
  rm -f junk

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

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

  1. компілятор C ++ час від часу дає мені кращі попереджувальні повідомлення, ніж компілятор C.
  2. Компілятор C ++ приймає параметр -Weffc ++, який час від часу дає мені корисні поради, які я б пропустив, якби я скомпілював це лише у простому С.
  3. Я можу тримати код порівняно легко для порту на C ++, уникаючи декількох граничних умов, коли звичайний код C є недійсним кодом C ++ (наприклад, визначення змінної з назвою "bool").

Так, я безнадійно оптимістична Pollyanna, яка продовжує думати, що напевно щомісяця, коли одна платформа буде або оголошена застарілою, або отримає гідний компілятор C ++, і ми можемо нарешті перейти на C ++. На мій погляд, це неминуче - питання лише в тому, чи станеться це до або після того, як керівництво нарешті видасть усім поні. :-)


Хороший момент із написанням його як C ++, я вважаю це часто. (підмножина природно)
Matt Joiner

6
Я мушу зазначити, що знесилення C на користь C ++ ніколи не відбудеться, вибачте :)
Метт Столяр

4
вважати -o / dev / null замість rm -f junk
ulidtko

9
-Wstrict-prototypes -Wmissing-prototypes

10
І -Wold-style-definitionякщо вам доведеться мати справу з рецидивістами, які вважають, що функції стилю K&R є гарною ідеєю, навіть із прототипами декларацій. (Мені доводиться мати справу з такими людьми. Мені це дійсно дратує, коли я знаходжу новий код, написаний на K&R. Досить погано мати застарілі речі K&R, які не виправлені, але новий код! Груба !!!)
Джонатан Леффлер,

9

Ось чудовий прапор, про який не згадували:

-Werror-implicit-function-declaration

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


8
man gcc

Посібник рясніє цікавими прапорами з хорошими описами. Однак, -Wall, ймовірно, зробить gcc максимально багатослівним. Якщо ви хочете отримати більше цікавих даних, вам слід поглянути на valgrind чи інший інструмент для перевірки на наявність помилок.


1
Хоча це loooooooooooooooooooooooooooooooong, хоч. man gcc | nlповідомляє понад 11000 рядків. Це більше, ніж сумнозвісна сторінка bash!
new123456

12
Слава Богу, вони забили його на чоловічій сторінці, замість однієї з цих богоугодних непрохідних "інформаційних" сторінок.
Метт Столяр

6

Ну, теж -Wextraповинні бути стандартними. -Werrorперетворює попередження в помилки (що може дуже дратувати, особливо якщо ви збираєтеся без -Wno-unused-result). -pedanticв поєднанні з std=c89дає додаткові попередження, якщо ви використовуєте функції C99.

Але саме про це. Ви не можете налаштувати компілятор C на щось більш збережене типу, ніж сам C.


6

-M* сім'я варіантів.

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

Ось приклад надзвичайно загального makefile із використанням -MD та -MP, який складе каталог, повний файлів c ++ вихідних та заголовків, та автоматично визначить усі залежності:

CPPFLAGS += -MD -MP                                         
SRC = $(wildcard *.cpp)                                                       

my_executable: $(SRC:%.cpp=%.o)                                                        
        g++ $(LDFLAGS) -o $@ $^                                               

-include $(SRC:%.cpp=%.d)

Ось допис у блозі, який детальніше обговорює це: http://www.microhowto.info/howto/automatically_generate_makefile_dependency.html


6

Є -Werror, яка трактує всі попередження як помилки та зупиняє компіляцію. На gccсторінці керівництва пояснено кожен перемикач командного рядка для вашого компілятора.


@Matt Joiner: Оскільки ви не згадали, яку машинну архітектуру використовуєте, gccпрапори можуть відрізнятися між вашими та будь-якими посиланнями, хто б хто не запропонував. Ось чому сторінки з інструкціями постачаються разом із вашим програмним забезпеченням.
Грег Хьюгілл

4

-Wfloat-equal

Від: http://mces.blogspot.com/2005/07/char-const-argv.html

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


10
Мої поплавці дійсно збігаються з рівністю, як я знаю , що я роблю.
Roland Illig

4

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

-Wformat=2прапор

-Wformat=> Перевірте виклики до printfта scanfін., Щоб переконатися, що надані аргументи мають типи, відповідні вказаному рядку формату ...

І дійсно важлива частина щодо цього ( згідно з посібником GCC ):

-Wformatвключено до -Wall. Для більшого контролю над деякими аспектами формату перевірки, параметри -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-security, і -Wformat=2доступні, але не включені в -Wall.`

Отже, тільки те, що у вас є -Wall, не означає, що у вас є все. ;)


3

Я іноді використовую -sдля набагато меншого виконуваного файлу:

-s
    Remove all symbol table and relocation information from the executable.

Джерело: http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options


6
вам слід просто запустити stripсвій двійковий файл, таким чином ви можете мати бінарний файл з інформацією про налагодження, видалити його пізніше для розповсюдження.
Hasturkun

Так, stripтеж працює, але -sможе бути швидше і простіше, хоча це не так складно, як бігstrip
Василь Шарапов

3

Хоча ця відповідь може бути трохи поза темою, і це питання є вагомим +1 від мене

Мене особливо цікавлять будь-які додаткові попередження та / або перетворення попереджень на помилки в деяких випадках, щоб абсолютно мінімізувати будь-які випадкові невідповідності.
є інструмент, який повинен виявити ВСІ помилки та потенційні помилки, які можуть не бути очевидними, є осколок, який IMHO робить набагато кращу роботу в пошуку помилок порівняно з gcc або будь-яким іншим компілятором з цього питання. Це гідний інструмент, який можна мати в скрині.

Статична перевірка за допомогою інструменту типу "ворсинка", такого як шина, повинна бути частиною ланцюжка інструментів компілятора.


Це завжди показує, що помилка не може подати файл препроцесора в C: \ include, я не впевнений, що робити
Suraj Jain

2

Мене особливо цікавлять будь-які додаткові попередження,

Окрім того -Wall, параметр -Wor -Wextra( -Wпрацює як із старими версіями gcc, так і з більш новими; більш новіші версії підтримують альтернативну назву -Wextra, що означає те саме, але є більш описовим) дає можливість отримати додаткові попередження.

Також є ще більше попереджень, які не вмикаються жодним із них, як правило, щодо сумнівно поганих речей. Набір доступних опцій залежить від того, яку версію gcc ви використовуєте - проконсультуйтеся man gccабо info gccдетальніше, або перегляньте онлайн-документацію на конкретну версію gcc, яка вас цікавить. І -pedanticвидає всі попередження, необхідні для конкретного стандарту, який використовується (що залежить на інші варіанти, такі як -std=xxxабо -ansi), і скаржиться на використання розширень gcc.

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

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

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


4
"Я не думаю, що gcc дозволяє вам робити це вибірково для конкретних попереджень." Власне, можна і з -Werror=some-warning.
Меттью Флашен

0
  • -Wmissing-prototypes: Якщо глобальна функція визначена без попереднього оголошення прототипу.
  • -Wformat-security: Попереджає про використання функцій формату, які представляють можливі проблеми безпеки. В даний час це попереджає про виклики printfта scanfфункції, коли рядок формату не є літеральним рядком і немає аргументів формату

0
  • -Werror=return-type: Застосовуйте помилку, коли функція не повертається в gcc. Він знаходиться /we4716у Visual Studio.

  • -Werror=implicit-function-declaration: Примусово помилка, коли функція використовується без визначеного / не включеного. Він знаходиться /we4013у Visual Studio.

  • -Werror=incompatible-pointer-types: Помилка перед тим, коли тип вказівника не відповідає сумі очікуваного типу. Він знаходиться /we4133у Visual Studio.

Насправді я хотів би зберегти свій код C крос-платформою, і я використовую CMake, і я розміщую надані cflags в CMakeLists.txt, як:

if (CMAKE_SYSTEM_NAME MATCHES "Windows")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4013 /we4133 /we4716")
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -Werror=return-type")
endif()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.