Przydatne flagi GCC dla C

157

Oprócz ustawiania -Walli ustawiania -std=XXX, jakie inne naprawdę przydatne, ale mniej znane flagi kompilatora są dostępne do użytku w C?

Szczególnie interesują mnie wszelkie dodatkowe ostrzeżenia i / lub przekształcanie ostrzeżeń w błędy w niektórych przypadkach, aby całkowicie zminimalizować wszelkie przypadkowe niezgodności typów.

Matt Joiner
źródło
9
Cóż -save-temps, -Wshadowi -fmudflapbyły to największe znaleziska, o których nie wiedziałem, dzięki wszystkim.
Matt Joiner,
Kontekst, o ile wiem: bieganie, gcc -c [flags-go-here] -o myprog.o myprog.caby skompilować (nie połączyć) program w C.
Rory O'Kane,

Odpowiedzi:

64

Kilka -fopcji generowania kodu jest interesujących:

  • -ftrapvFunkcja powoduje przerwanie programu w liczba całkowita ze znakiem przelewowy (formalnie „zdefiniowana zachowanie” w C).

  • -fverbose-asmjest przydatny, jeśli kompilujesz z, -Saby zbadać wyjście zestawu - dodaje kilka pouczających komentarzy.

  • -finstrument-functions dodaje kod wywołujący funkcje profilowania dostarczone przez użytkownika w każdym punkcie wejścia i wyjścia funkcji.

kawiarnia
źródło
Bo -ftrapvzajrzyj tutaj stackoverflow.com/questions/20851061/… .. wygląda na to, że błąd długo czekał na naprawę.
Arjun Sreedharan
Czy możesz sprawdzić powyższy komentarz?
Suraj Jain
-ftrapv zostało zasadniczo zastąpione przez -fsanitize = przepełnienie-liczby całkowitej ze znakiem.
Marc Glisse,
139

Oto moje:

  • -Wextra, -Wall: niezbędny.
  • -Wfloat-equal: przydatne, ponieważ zwykle testowanie liczb zmiennoprzecinkowych pod kątem równości jest złe.
  • -Wundef: ostrzeż, jeśli niezainicjowany identyfikator jest oceniany w #ifdyrektywie.
  • -Wshadow: ostrzegaj za każdym razem, gdy zmienna lokalna przesłania inną zmienną lokalną, parametr lub zmienną globalną lub gdy funkcja wbudowana jest zasłonięta.
  • -Wpointer-arith: ostrzeż, jeśli cokolwiek zależy od rozmiaru funkcji lub void.
  • -Wcast-align: ostrzegaj za każdym razem, gdy wskaźnik jest rzucany w taki sposób, że wymagane wyrównanie celu jest zwiększone. Na przykład ostrzegaj, jeśli a char *jest rzutowane int *na maszynę, na której liczby całkowite są dostępne tylko w granicach dwu- lub czterobajtowych.
  • -Wstrict-prototypes: warn, jeśli funkcja jest zadeklarowana lub zdefiniowana bez określenia typów argumentów.
  • -Wstrict-overflow=5: ostrzega o przypadkach, w których kompilator optymalizuje na podstawie założenia, że ​​podpisane przepełnienie nie występuje. (Wartość 5 może być zbyt rygorystyczna, zobacz stronę podręcznika).
  • -Wwrite-strings: nadaje stałym łańcuchowym const char[długość typu ], aby kopiowanie adresu jednego do innegoconst char * wskaźnikiem otrzymało ostrzeżenie.
  • -Waggregate-return: ostrzega, jeśli jakiekolwiek funkcje zwracające struktury lub związki są zdefiniowane lub wywołane.
  • -Wcast-qual: ostrzegaj za każdym razem, gdy rzutowany jest wskaźnik w celu usunięcia kwalifikatora typu z typu docelowego * .
  • -Wswitch-default: ostrzegaj za każdym razem, gdy switchinstrukcja nie ma defaultprzypadku * .
  • -Wswitch-enum: ostrzegaj za każdym razem, gdy switchinstrukcja ma indeks typu wyliczeniowego i brakuje jej casedla jednego lub więcej nazwanych kodów tego wyliczenia * .
  • -Wconversion: ostrzegaj przed niejawnymi konwersjami, które mogą zmienić wartość * .
  • -Wunreachable-code: warn, jeśli kompilator wykryje, że kod nigdy nie zostanie wykonany * .

Te oznaczone * czasami dają zbyt wiele fałszywych ostrzeżeń, więc używam ich w razie potrzeby.

Alok Singhal
źródło
11
Całkiem pełna lista, po prostu chcę dodać jeszcze jedną; -Wformat=2: Dodatkowy format sprawdza funkcje printf / scanf.
schot
1
czy to wszystko nie jest implikowane -Wall?
chacham15
2
@ chacham15, nie, nie sądzę. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal,
1
@Alok hmm, może to nie jest standard wśród dystrybucji? Wiem, że na moim mbp muszę wyraźnie wyłączyć, -Wwrite-stringsponieważ tak bardzo go nienawidzę.
chacham15
@ chacham15, może. Ale opis -Wwrite-stringskonkretnie mówi, że nie jest on częścią -Wall: gcc.gnu.org/onlinedocs/gcc/… . Może coś innego w twojej konfiguracji ustawia tę flagę? A może kompilujesz C ++?
Alok Singhal,
52

Zawsze stosować -Olub powyżej ( -O1, -O2,-Os , itd.). Na domyślnym poziomie optymalizacji gcc dąży do szybkości kompilacji i nie przeprowadza wystarczającej analizy, aby ostrzegać o takich rzeczach, jak zmienne zjednostkowane.

Rozważ ustalenie -Werrorzasad, ponieważ ostrzeżenia, które nie zatrzymują kompilacji, są zwykle ignorowane.

-Wall prawie włącza ostrzeżenia, które najprawdopodobniej są błędami.

Ostrzeżenia zawarte w programie -Wextrazwykle oznaczają typowy, legalny kod. Mogą być przydatne do recenzji kodu (chociaż programy typu lint mają dużo więcej pułapek jest bardziej elastycznych), ale nie włączałbym ich do normalnego programowania.

-Wfloat-equal to dobry pomysł, jeśli programiści projektu nie znają zmiennoprzecinkowych, a zły pomysł, jeśli tak jest.

-Winit-selfjest przydatny; Zastanawiam się, dlaczego nie ma tego w -Wuninitialized.

-Wpointer-arithjest przydatny, jeśli masz kod w większości przenośny, z którym nie działa -pedantic.

Gilles 'SO- przestań być zły'
źródło
9
+1 dla „-Wfloat-equal” to dobry pomysł, jeśli programiści projektu nie znają zmiennoprzecinkowego punktu, a zły pomysł, jeśli tak jest. zwłaszcza w drugiej połowie. :-)
R .. GitHub STOP HELPING ICE
39
-save-temps

Pozostawia to wyniki preprocesora i asemblacji.

Wstępnie przetworzone źródło jest przydatne do debugowania makr.

Zespół jest przydatny do określenia, jakie optymalizacje zostały wprowadzone. Na przykład możesz chcieć sprawdzić, czy GCC optymalizuje wywołania końcowe w niektórych funkcjach rekurencyjnych, ponieważ bez niej możesz potencjalnie przepełnić stos.

catphive
źródło
Zastanawiałem się, jak udało ci się to zrobić ... Zawsze prosiłem gcc o zrzucenie zestawu, jeśli tego potrzebowałem.
35

Dziwię się, że nikt jeszcze tego nie powiedział - najbardziej użyteczną flagą, o ile mi -gwiadomo , jest umieszczanie informacji debugowania w pliku wykonywalnym, tak aby można było je zdebugować i przejść przez źródła (chyba że jesteś biegły i czytasz asembler i jak stepipolecenie) programu podczas jego wykonywania.


źródło
35

-fmudflap - dodaje testy uruchomieniowe do wszystkich ryzykownych operacji wskaźnikowych, aby złapać UB. To skutecznie uodparnia Twój program na przepełnienie bufora i pomaga wyłapać wszelkiego rodzaju wiszące wskazówki.

Oto demo:

$ 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
Nordic Mainframe
źródło
Hmmm, chlapacze wydają się dość paskudne: P
Matt Joiner
9
-fmudflapnie jest już obsługiwany od GCC 4.9 warning: switch '-fmudflap' is no longer supported. Został zastąpiony przez AddressSanitizer.
Agostino
21

Niezupełnie związane z C / C ++, ale i tak przydatne:

@file

Umieść wszystkie powyższe dobre flagi (które wszyscy określiliście) w „pliku” i użyj powyższej flagi, aby użyć razem wszystkich flag w tym pliku.

na przykład:

Plik: compilerFlags

-Ściana

-std = c99

-Wextra

Następnie skompiluj:

gcc yourSourceFile @compilerFlags
Amit Tomar
źródło
15

-march=native aby stworzyć zoptymalizowany kod dla platformy (= chipa), na którym kompilujesz

Jens Gustedt
źródło
2
Jeśli kompilujesz dla maszyn innych niż natywne, gdzie nie znasz celu, możesz użyć mtune = xxx, który optymalizuje bez używania zestawów instrukcji. Na przykład mtune = generic jest aktualizowana przez „przeciętne” procesory spraw.
Turix
15

Jeśli potrzebujesz znać flagi preprocesora, które są predefiniowane przez kompilator:

echo | gcc -E -dM -
sizzzzlerz
źródło
13

Nie jest to zbyt pomocne w wykrywaniu błędów, ale rzadko wspominana -masm=intelopcja sprawia, że ​​używa-S do sprawdzania wyników zespołu jest o wiele przyjemniejsze.

Składnia asemblera AT&T za bardzo boli mnie w głowę.

Michael Burr
źródło
2
Dla mnie różnica między AT&T i Intelem polega na różnicy między C # a Javą. Tylko składnia. Obie okropne. :)
Matt Joiner
2
+1 @michael za zmuszenie gcc do używania składni intel zamiast boga okropnego at & t. Inspekcja zespołu wykorzystuje wystarczającą liczbę cykli mózgowych - nie ma potrzeby marnowania cykli mózgowych, które src przechodzi przed przeznaczeniem w opkodach. Teraz, jeśli tylko gcc obsługuje wbudowane __asm ​​{}, jak inne kompilatory, jesteśmy gotowi!
greatwolf
10

Mój plik makefile zazwyczaj zawiera

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

Najważniejsze z tych opcji zostały omówione wcześniej, dlatego zwrócę uwagę na dwie funkcje, które nie zostały jeszcze wymienione:

Mimo że pracuję nad bazą kodu, która musi być zwykłym C, aby można było ją przenieść na jakąś platformę, która nadal nie ma porządnego kompilatora C ++, wykonuję „dodatkową” kompilację za pomocą kompilatora C ++ (oprócz kompilatora C). Ma to 3 zalety:

  1. kompilator C ++ czasami wyświetla lepsze komunikaty ostrzegawcze niż kompilator C.
  2. Kompilator C ++ akceptuje opcję -Weffc ++, która od czasu do czasu daje mi przydatne wskazówki, których bym przegapił, gdybym skompilował ją tylko w zwykłym C.
  3. Mogę stosunkowo łatwo przenieść kod do C ++, unikając kilku warunków brzegowych, w których zwykły kod C jest nieprawidłowym kodem w C ++ (takich jak zdefiniowanie zmiennej o nazwie „bool”).

Tak, jestem beznadziejnie optymistyczną Pollyanną, która wciąż myśli, że z pewnością w każdym miesiącu jedna platforma zostanie uznana za przestarzałą lub zdobędzie porządny kompilator C ++ i możemy wreszcie przejść na C ++. Moim zdaniem jest to nieuniknione - pozostaje tylko pytanie, czy dzieje się to przed, czy po tym, jak zarząd ostatecznie wyda każdemu kucyka. :-)

David Cary
źródło
Dobrze napisać to jako C ++, często o tym myślę. (podzbiór naturalnie)
Matt Joiner
6
Powinienem zaznaczyć, że przestarzałe C na rzecz C ++ nigdy się nie wydarzy, przepraszam :)
Matt Joiner
4
rozważ -o / dev / null zamiast rm -f śmieci
ulidtko
9
-Wstrict-prototypes -Wmissing-prototypes
ninjalj
źródło
10
A -Wold-style-definitionjeśli masz do czynienia z recydywistami, którzy uważają, że funkcje w stylu K&R są dobrym pomysłem, nawet z prototypowymi deklaracjami. (Muszę mieć do czynienia z takimi ludźmi. Naprawdę denerwuje mnie, gdy znajduję nowy kod napisany w K&R. Wystarczająco źle jest mieć starsze elementy K&R, które nie są naprawione, ale nowy kod! Grump !!!)
Jonathan Leffler
9

Oto wspaniała flaga, o której nie wspomniano:

-Werror-implicit-function-declaration

Podaj błąd za każdym razem, gdy funkcja jest używana przed zadeklarowaniem.

Matt Joiner
źródło
8
man gcc

Podręcznik jest pełen ciekawych flag z dobrymi opisami. Jednak -Wall prawdopodobnie sprawi, że gcc będzie tak rozwlekłe, jak to tylko możliwe. Jeśli potrzebujesz bardziej interesujących danych, powinieneś rzucić okiem na valgrind lub inne narzędzie do sprawdzania błędów.

Johan
źródło
1
Jest jednak loooooooooooooooooooooooooooooooong. man gcc | nlzgłasza ponad 11000 linii. To więcej niż niesławna strona bashpodręcznika!
nowy123456
12
Dzięki Bogu, wcisnęli go na stronę podręcznika, zamiast na jednej z tych okropnych, niemożliwych do przejrzenia stron "informacyjnych".
Matt Joiner
6

Cóż, też -Wextrapowinno być standardowe. -Werrorzamienia ostrzeżenia w błędy (co może być bardzo irytujące, zwłaszcza jeśli kompilujesz bez niej -Wno-unused-result). -pedanticw połączeniu zstd=c89 daje dodatkowe ostrzeżenia, jeśli używasz funkcji C99.

Ale to jest o tym. Nie można dostroić kompilatora C do czegoś bardziej zachowującego typy niż sam C.

RWS
źródło
6

-M* rodzina opcji.

Umożliwiają one pisanie plików, które automatycznie określają, od jakich plików nagłówkowych powinny zależeć pliki źródłowe c lub c ++. GCC wygeneruje pliki make z tymi informacjami o zależnościach, a następnie dodasz je do swojego podstawowego pliku make.

Oto przykład niezwykle ogólnego pliku makefile używającego -MD i -MP, który skompiluje katalog pełen plików źródłowych i nagłówkowych języka c ++ i automatycznie obliczy wszystkie zależności:

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

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

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

Oto post na blogu, który omawia to bardziej szczegółowo: http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html

catphive
źródło
6

Jest -Werror, który traktuje wszystkie ostrzeżenia jako błędy i zatrzymuje kompilację. Strona gccpodręcznika wyjaśnia wszystkie przełączniki wiersza poleceń dla twojego kompilatora.

Greg Hewgill
źródło
@Matt Joiner: Ponieważ nie wspomniałeś o używanej architekturze maszyny, gccflagi mogą się różnić między twoją i jakimkolwiek linkiem, który ktoś zasugeruje. Dlatego z oprogramowaniem dostarczane są strony podręcznika.
Greg Hewgill
4

-Wfloat-equal

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

Jednym z innych nowych ostrzeżeń, które mi się podobają, jest -Wfloat-equal. Ten ostrzega za każdym razem, gdy [masz] liczbę zmiennoprzecinkową w warunku równości. To wspaniałe! Jeśli każdy zaprogramowałeś grafikę komputerową lub (co gorsza :) algorytm geometrii obliczeniowej, wiesz, że żadne dwa zmiennoprzecinkowe nigdy nie pasują do równości ...

stadnina
źródło
10
Moi pływaki nie zgadza się z równością, jak wiem, co robię.
Roland Illig
4

Znalazłem ten wątek, szukając flagi do naprawienia konkretnego problemu, nie widzę tego tutaj, więc dodam taki, który właśnie wbijał mnie w mój post :

-Wformat=2flag

-Wformat=> Sprawdź wywołania printfi scanfitp., Aby upewnić się, że podane argumenty mają typy odpowiednie do określonego ciągu formatu ...

I naprawdę ważna część na ten temat ( zgodnie z instrukcją GCC ):

-Wformatjest zawarte w -Wall. Aby uzyskać większą kontrolę nad niektórymi aspektami formacie sprawdzających, opcje -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-security, i -Wformat=2są dostępne, ale nie są wliczone w -Wall.`

A więc to, że masz, -Wallnie oznacza, że ​​masz wszystko. ;)

Mikrofon
źródło
3

Czasami używam -sdo znacznie mniejszego pliku wykonywalnego:

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

Źródło: http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options

Wasilij Szarapow
źródło
6
powinieneś po prostu uruchomić stripswój plik binarny, w ten sposób możesz mieć plik binarny z informacjami debugowania, a następnie usunąć go do dystrybucji.
Hasturkun
Tak, stripteż działa, ale -smoże być szybsze i łatwiejsze, chociaż nie jest tak wyszukane jak bieganiestrip
Vasiliy Sharapov
3

Chociaż ta odpowiedź może być nieco nie na temat, a pytanie jest godne +1 ode mnie, ponieważ

Szczególnie interesują mnie wszelkie dodatkowe ostrzeżenia i / lub przekształcanie ostrzeżeń w błędy w niektórych przypadkach, aby całkowicie zminimalizować wszelkie przypadkowe niezgodności typów.
jest narzędzie, które powinno wychwycić WSZYSTKIE błędy i potencjalne błędy, które mogą nie być oczywiste, jest też szyna, której IMHO lepiej radzi sobie z wyłapywaniem błędów w porównaniu z gcc lub jakimkolwiek innym kompilatorem. To wartościowe narzędzie, które warto mieć w swojej skrzynce z narzędziami.

Statyczne sprawdzanie za pomocą narzędzia typu lint, takiego jak szyna, powinno być częścią łańcucha narzędzi kompilatora.

t0mm13b
źródło
Zawsze pokazuje błąd, nie można zapisać pliku preprocesora w C: \ include, nie jestem pewien, co zrobić
Suraj Jain
2

Jestem szczególnie zainteresowany dodatkowymi ostrzeżeniami,

Oprócz -WallThe -Walbo -Wextraopcja ( -Wwspółpracuje ze starszymi wersjami GCC, jak również nowsze; nowsze wersje obsługują alternatywną nazwę -Wextra, co oznacza to samo, ale jest bardziej opisowy) umożliwia różne dodatkowe ostrzeżenia.

Jest jeszcze więcej ostrzeżeń, które nie są włączane przez żadną z nich, generalnie dla rzeczy, które są bardziej wątpliwe. Zestaw dostępnych opcji zależy od używanej wersji gcc - skonsultuj man gcclubinfo gcc po szczegóły, albo zajrzyj do dokumentacji online dla konkretnej wersji gcc, którą jesteś zainteresowany. I wyświetla -pedanticwszystkie ostrzeżenia wymagane przez konkretny używany standard (co zależy na innych opcjach, takich jak -std=xxxlub -ansi) i narzeka na użycie rozszerzeń gcc.

i / lub zamienianie ostrzeżeń w błędy w niektórych przypadkach, aby całkowicie zminimalizować wszelkie przypadkowe niezgodności typów.

-Werrorzamienia wszystkie ostrzeżenia w błędy. Nie sądzę jednak, aby gcc pozwalało na to selektywnie w przypadku określonych ostrzeżeń.

Prawdopodobnie okaże się, że musisz selektywnie wybierać, które ostrzeżenia są włączone dla każdego projektu (zwłaszcza jeśli używasz -Werror), ponieważ pliki nagłówkowe z bibliotek zewnętrznych mogą powodować problemy z niektórymi z nich. ( -pedanticw szczególności wydaje mi się, że nie jest to pomocne w tym względzie, z mojego doświadczenia).

Matthew Slattery
źródło
4
„Nie sądzę jednak, by gcc pozwalało ci to robić selektywnie w przypadku określonych ostrzeżeń”. Właściwie możesz z -Werror=some-warning.
Matthew Flaschen,
0
  • -Wmissing-prototypes: Jeśli funkcja globalna jest zdefiniowana bez wcześniejszej deklaracji prototypu.
  • -Wformat-security: Ostrzega przed używaniem funkcji formatu, które stanowią potencjalne problemy z bezpieczeństwem. Obecnie ostrzega to o wywołaniach printfi scanffunkcjach, w których ciąg formatu nie jest literałem ciągu i nie ma argumentów formatu
Praveen Handigol
źródło
0
  • -Werror=return-type: Wymuś błąd, gdy funkcja nie zwraca w gcc. Jest /we4716w Visual Studio.

  • -Werror=implicit-function-declaration: Wymuś błąd, gdy funkcja jest używana bez zdefiniowanej / nieuwzględnionej. Jest /we4013w Visual Studio.

  • -Werror=incompatible-pointer-types: Oznacza błąd, gdy typ wskaźnika jest niezgodny z oczekiwanym typem wskaźnika. Jest /we4133w Visual Studio.

Właściwie chciałbym, aby mój kod w C był międzyplatformowy, używam CMake i umieszczam dostarczone cflagi w CMakeLists.txt w następujący sposób:

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
źródło