Полезные флаги GCC для C

157

Помимо настройки -Wallи настройки -std=XXX, какие еще действительно полезные, но менее известные флаги компилятора существуют для использования в C?

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

Мэтт Джойнер
источник
9
Ну -save-temps, -Wshadowи -fmudflapбыли величайшими находками, о которых я не знал, спасибо всем.
Мэтт Джойнер
Контекст, насколько я могу судить: запуск gcc -c [flags-go-here] -o myprog.o myprog.cдля компиляции (а не ссылки) программы на Си.
Рори О'Кейн

Ответы:

64

Несколько -fвариантов генерации кода интересны:

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

  • -fverbose-asmполезно, если вы компилируете с помощью -Sдля проверки вывода сборки - он добавляет некоторые информативные комментарии.

  • -finstrument-functions добавляет код для вызова пользовательских профилирующих функций в каждой точке входа и выхода функции.

кафе
источник
Для -ftrapv, посмотрите здесь stackoverflow.com/questions/20851061/… .. похоже, есть ошибка, долго ожидающая, чтобы быть исправленной.
Арджун Шридхарен
Можете ли вы проверить вышеуказанный комментарий?
Сурадж Джейн
-ftrapv был по существу заменен на -fsanitize = sign-integer-overflow.
Марк Глисс,
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: warn всякий раз, когда у switchоператора есть индекс перечислимого типа и отсутствует caseодин или несколько именованных кодов этого перечисления * .
  • -Wconversion: предупреждение для неявных преобразований, которые могут изменить значение * .
  • -Wunreachable-code: предупредить, если компилятор обнаружит, что код никогда не будет выполнен * .

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

Алок Сингхал
источник
11
Довольно полный список, просто хочу добавить еще один; -Wformat=2: Дополнительные проверки формата в функциях printf / scanf.
Скот
1
Разве все это не подразумевается -Wall?
chacham15
2
@ chacham15, нет, я так не думаю. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Алок Сингхал,
1
@Alok хм, может быть, это не стандартно среди дистрибутивов? Я знаю, что на моем MBP я должен явно отключить, -Wwrite-stringsпотому что я ненавижу это так сильно.
chacham15
@ chacham15, может быть. Но в описании -Wwrite-stringsспециально сказано, что оно не является частью -Wall: gcc.gnu.org/onlinedocs/gcc/… . Может быть, что-то еще в вашей настройке устанавливает этот флаг? Или, может быть, вы компилируете C ++?
Алок Сингхал
52

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

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

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

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

-Wfloat-equal хорошая идея, если разработчики проекта не знакомы с плавающей запятой, и плохая идея, если они есть.

-Winit-selfявляется полезным; Интересно, почему это не входит в -Wuninitialized.

-Wpointer-arithполезно, если у вас есть в основном переносимый код, с которым не работает -pedantic.

Жиль "ТАК - прекрати быть злым"
источник
9
+1 для «-Wfloat-equal» - хорошая идея, если разработчики проекта не знакомы с плавающей запятой, и плохая идея, если они есть ». особенно вторая половина этого. :-)
R .. GitHub ОСТАНОВИТЬ ПОМОЩЬ ICE
39
-save-temps

Это оставляет позади результаты препроцессора и сборки.

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

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

catphive
источник
Мне было интересно, как ты это сделал ... Я всегда просто просил 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

-Wall

-std = C99

-Wextra

Затем скомпилируйте:

gcc yourSourceFile @compilerFlags
Амит Томар
источник
15

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

Йенс Гастедт
источник
2
Если вы компилируете для не собственных машин, где вы не знаете цель, вы можете использовать mtune = xxx, которая оптимизирует без использования наборов команд. Например, mtune = generic поддерживается в актуальном состоянии для процессоров среднего уровня.
Турикс
15

Если вам нужно знать флаги препроцессора, которые предопределены компилятором:

echo | gcc -E -dM -
sizzzzlerz
источник
13

Это не очень полезно для обнаружения ошибок, но редко упоминаемая -masm=intelопция делает использование-S для проверки вывода сборки намного более приятным.

Синтаксис сборки AT & T слишком сильно ранит мою голову.

Майкл Берр
источник
2
Разница между AT & T и Intel для меня заключается в разнице между C # и Java. Просто синтаксис. Оба ужасные. :)
Matt Joiner
2
+1 @ michael за то, что заставил gcc использовать синтаксис intel вместо ужасного бога в & t. При проверке сборки используется достаточно мозговых циклов - не нужно тратить мозговые циклы, которые выполняются src до использования кодов операций. Теперь, если только gcc поддерживает встроенный __asm ​​{}, как и другие компиляторы, мы готовы!
великий волк
10

Мой make-файл обычно содержит

  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 ++, которая иногда дает мне несколько полезных советов, которые я бы упустил, если бы я компилировал их только в простом C.
  3. Я могу сохранить код относительно простым для переноса на C ++, избегая нескольких граничных условий, когда простой код C является недопустимым кодом C ++ (например, определение переменной с именем "bool").

Да, я безнадежно оптимистичная Поллианна, которая постоянно думает, что в любой месяц наверняка одна платформа будет либо объявлена ​​устаревшей, либо получит достойный компилятор C ++, и мы наконец сможем переключиться на C ++. На мой взгляд, это неизбежно - вопрос только в том, произойдет ли это до или после того, как руководство наконец выпустит всех пони. :-)

David Cary
источник
Хороший момент при написании этого на C ++, я часто об этом думаю. (естественно, подмножество)
Matt Joiner
6
Я должен отметить, что C не рекомендуется в пользу C ++, никогда не произойдет, извините :)
Matt Joiner
4
рассмотрите -o / dev / null вместо rm -f мусор
ulidtko
9
-Wstrict-prototypes -Wmissing-prototypes
ninjalj
источник
10
И -Wold-style-definitionесли вам приходится иметь дело с рецидивистами, которые считают, что функции в стиле K & R - хорошая идея, даже с объявлениями-прототипами. (Мне приходится иметь дело с такими людьми. Меня действительно раздражает, когда я нахожу новый код, написанный на K & R. Достаточно плохо иметь устаревшие K & R-материалы, которые не исправлены, но новый код! Grump !!!)
Джонатан Леффлер
9

Вот отличный флаг, который не был упомянут:

-Werror-implicit-function-declaration

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

Мэтт Джойнер
источник
8
man gcc

Руководство полно интересных флагов с хорошими описаниями. Тем не менее, -Wall, вероятно, сделает GCC максимально подробным. Если вам нужны более интересные данные, вы должны взглянуть на valgrind или другой инструмент для проверки ошибок.

Johan
источник
1
Хотя это и есть ооооооооооооооооооооооооо. man gcc | nlсообщает более 11000 строк. Это больше, чем печально известная bashстраница!
new123456
12
Слава богу, они втиснули его в справочную страницу, вместо одной из этих чудовищных неиссякаемых «информационных» страниц.
Matt Joiner
6

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

Но это все. Вы не можете настроить компилятор C на что-то более сохраняющее тип, чем сам C.

RWS
источник
6

-M* Семья вариантов.

Они позволяют вам писать make-файлы, которые автоматически выясняют, от каких файлов заголовков должны зависеть ваши исходные файлы c или c ++. GCC создаст файлы make с этой информацией о зависимостях, а затем вы включите их в свой основной файл make.

Вот пример чрезвычайно универсального make-файла с использованием -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/automatics_generate_makefile_dependencies.html

catphive
источник
6

Существует -Werror, который обрабатывает все предупреждения как ошибки и останавливает компиляцию. Страница gccруководства объясняет каждый параметр командной строки для вашего компилятора.

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

-Wfloat-equal

От: http://mces.blogspot.com/2005/07/char-const-argv.html

Еще одно новое предупреждение, которое мне нравится, это -Wfloat-equal. Этот предупреждает всякий раз, когда у вас [есть] число с плавающей точкой в ​​условии равенства. Это великолепно! Если у вас есть все запрограммированные алгоритмы компьютерной графики или (что еще хуже :) вычислительной геометрии, вы знаете, что никакие два числа с плавающей запятой никогда не совпадают с равенством ...

шпилька
источник
10
Мои поплавки действительно совпадают с равенством, как я знаю , что я делаю.
Роланд Иллиг
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 или любым другим компилятором в этом отношении. Это достойный инструмент в вашем сундуке с инструментами.

Статическая проверка с помощью инструмента типа lint, такого как splint, должна была быть частью цепочки инструментов компилятора.

t0mm13b
источник
Это всегда показывает, что ошибка не может подать файл препроцессора в 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()
HaxtraZ
источник