Bendera GCC yang berguna untuk C


157

Di luar pengaturan -Wall, dan pengaturan -std=XXX, apa lagi yang benar-benar berguna, tetapi flag-flag compiler yang kurang dikenal tersedia untuk digunakan di C?

Saya sangat tertarik dengan peringatan tambahan, dan / atau mengubah peringatan menjadi kesalahan dalam beberapa kasus untuk benar-benar meminimalkan ketidakcocokan jenis yang tidak disengaja.


9
Ya -save-temps, -Wshadowdan -fmudflapmerupakan penemuan terhebat yang tidak saya ketahui, terima kasih untuk semuanya.
Matt Joiner

Konteks, sejauh yang saya tahu: menjalankan gcc -c [flags-go-here] -o myprog.o myprog.cuntuk mengkompilasi (bukan tautan) program C.
Rory O'Kane

Jawaban:


64

Beberapa -fopsi pembuatan kode menarik:

  • The -ftrapvfungsi akan menyebabkan program untuk membatalkan pada integer ditandatangani overflow (resmi "perilaku undefined" di C).

  • -fverbose-asmberguna jika Anda mengkompilasi dengan -Suntuk memeriksa hasil perakitan - itu menambahkan beberapa komentar informatif.

  • -finstrument-functions menambahkan kode untuk memanggil fungsi profil yang disediakan pengguna di setiap entri fungsi dan titik keluar.


Untuk -ftrapv, lihat di sini stackoverflow.com/questions/20851061/… .. sepertinya ada bug yang lama menunggu untuk diperbaiki.
Arjun Sreedharan

Bisakah Anda Memeriksa Komentar Di Atas?
Suraj Jain

-ftrapv pada dasarnya digantikan oleh -fsanitize = signed-integer-overflow.
Marc Glisse

139

Ini milik saya:

  • -Wextra, -Wall: esensial.
  • -Wfloat-equal: berguna karena biasanya menguji angka floating-point untuk kesetaraan adalah buruk.
  • -Wundef: memperingatkan jika pengidentifikasi yang tidak diinisialisasi dievaluasi dalam #ifarahan.
  • -Wshadow: beri peringatan kapan pun variabel lokal memberi bayangan variabel lokal lain, parameter atau variabel global, atau setiap kali fungsi bawaan dibayangi.
  • -Wpointer-arith: memperingatkan jika ada yang tergantung pada ukuran fungsi atau void.
  • -Wcast-align: peringatkan setiap kali pointer dilemparkan sedemikian rupa sehingga keselarasan yang diperlukan dari target meningkat Sebagai contoh, ingatkan jika a char *dilemparkan ke int *mesin di mana bilangan bulat hanya dapat diakses pada batas dua atau empat byte.
  • -Wstrict-prototypes: memperingatkan jika suatu fungsi dideklarasikan atau didefinisikan tanpa menentukan jenis argumen.
  • -Wstrict-overflow=5: memperingatkan tentang kasus-kasus di mana kompiler mengoptimalkan berdasarkan asumsi bahwa limpahan yang ditandatangani tidak terjadi. (Nilai 5 mungkin terlalu ketat, lihat halaman manual.)
  • -Wwrite-strings: berikan string konstanta const char[panjang jenis ]sehingga menyalin alamat satu ke non- const char *pointer akan mendapat peringatan.
  • -Waggregate-return: memperingatkan jika ada fungsi yang mengembalikan struktur atau serikat didefinisikan atau dipanggil.
  • -Wcast-qual: peringatkan setiap kali sebuah pointer dilemparkan untuk menghapus kualifikasi tipe dari tipe target * .
  • -Wswitch-default: peringatkan setiap kali switchpernyataan tidak memiliki defaultkasus * .
  • -Wswitch-enum: beri peringatan setiap kali switchpernyataan memiliki indeks tipe enumerasi dan tidak memiliki caseuntuk satu atau lebih kode nama enumerasi itu * .
  • -Wconversion: beri peringatan untuk konversi tersirat yang dapat mengubah nilai * .
  • -Wunreachable-code: peringatkan jika kompiler mendeteksi bahwa kode tidak akan pernah dieksekusi * .

Yang ditandai * terkadang memberikan terlalu banyak peringatan palsu, jadi saya menggunakannya sesuai kebutuhan.


11
Daftar yang cukup lengkap, hanya ingin menambahkan satu lagi; -Wformat=2: Pemeriksaan format ekstra pada fungsi printf / scanf.
schot

1
Bukankah semua ini disiratkan oleh -Wall?
chacham15

2
@ chacham15, tidak, kurasa tidak. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal

1
@Lok hmm, mungkin itu bukan standar di antara distribusi? Saya tahu bahwa pada mbp saya harus mematikannya secara eksplisit -Wwrite-stringskarena saya sangat membencinya.
chacham15

@ chacham15, mungkin. Tetapi deskripsi untuk -Wwrite-stringssecara khusus mengatakan itu bukan bagian dari -Wall: gcc.gnu.org/onlinedocs/gcc/… . Mungkin ada hal lain dalam pengaturan Anda yang mengatur bendera itu? Atau mungkin Anda sedang mengkompilasi C ++?
Alok Singhal

52

Selalu gunakan -Oatau di atas ( -O1, -O2, -Os, dll). Pada tingkat optimasi default, gcc pergi untuk kecepatan kompilasi dan tidak melakukan analisis yang cukup untuk memperingatkan tentang hal-hal seperti variabel unitial.

Pertimbangkan membuat -Werrorkebijakan, karena peringatan yang tidak menghentikan kompilasi cenderung diabaikan.

-Wall cukup banyak menyalakan peringatan yang sangat mungkin menjadi kesalahan.

Peringatan yang termasuk dalam -Wextracenderung menandai kode yang umum dan sah. Mereka mungkin berguna untuk ulasan kode (meskipun program bergaya tidak menemukan banyak jebakan lebih fleksibel), tapi saya tidak akan menyalakannya untuk pengembangan normal.

-Wfloat-equal adalah ide yang baik jika pengembang pada proyek tidak terbiasa dengan floating point, dan ide yang buruk jika ya.

-Winit-selfberguna; Saya bertanya-tanya mengapa itu tidak termasuk dalam -Wuninitialized.

-Wpointer-arithberguna jika Anda memiliki kebanyakan kode portabel yang tidak berfungsi -pedantic.


9
+1 untuk "-Wfloat-equal adalah ide bagus jika pengembang pada proyek tidak terbiasa dengan floating point, dan ide buruk jika mereka." terutama bagian kedua itu. :-)
R .. GitHub BERHENTI MEMBANTU ICE

39
-save-temps

Ini meninggalkan hasil preprocessor dan perakitan.

Sumber preprocessed berguna untuk debugging macro.

Perakitan berguna untuk menentukan optimasi apa yang berlaku. Misalnya, Anda mungkin ingin memverifikasi bahwa GCC melakukan optimasi panggilan ekor pada beberapa fungsi rekursif, karena tanpa itu Anda berpotensi meluap tumpukan.


Saya bertanya-tanya bagaimana Anda bisa melakukannya ... Saya selalu meminta gcc untuk membuang perakitan jika saya membutuhkannya.

35

Saya terkejut belum ada yang mengatakan ini - flag yang paling berguna sejauh yang saya ketahui adalah -gyang menempatkan informasi debug ke dalam executable sehingga Anda dapat men-debug dan melangkah melalui sumber (kecuali jika Anda mahir dan membaca perakitan dan seperti stepiperintah) dari suatu program ketika sedang dieksekusi.


35

-fmudflap - menambahkan pemeriksaan runtime ke semua operasi pointer berisiko untuk menangkap UB. Ini secara efektif mengimunisasi program Anda lagi buffer overflows dan membantu untuk menangkap semua jenis pointer menggantung.

Ini 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

Hmmm, mudflap sepertinya cukup jahat: P
Matt Joiner

9
-fmudflaptidak lagi didukung sejak GCC 4.9, Anda dapatkan warning: switch '-fmudflap' is no longer supported. Itu digantikan oleh AddressSanitizer.
Agostino

21

Tidak benar-benar terkait dengan C / C ++, tetapi bermanfaat:

@file

Letakkan semua flag yang baik di atas (yang telah Anda tentukan) dalam 'file', dan gunakan flag di atas untuk menggunakan semua flag dalam file tersebut.

misalnya:

File: compilerFlags

-Dinding

-std = c99

-Wextra

Kemudian kompilasi:

gcc yourSourceFile @compilerFlags

15

-march=native untuk menghasilkan kode yang dioptimalkan untuk platform (= chip) yang Anda kompilasi


2
Jika Anda mengkompilasi untuk mesin non-asli di mana Anda tidak tahu target, Anda dapat menggunakan mtune = xxx yang dioptimalkan tanpa menggunakan set instruksi. Misalnya mtune = generik selalu diperbarui dengan prosesor kasus "rata-rata".
Turix

15

Jika Anda perlu mengetahui flag preprocessor yang telah ditentukan oleh kompiler:

echo | gcc -E -dM -

13

Ini tidak benar-benar membantu untuk mendeteksi kesalahan, tetapi opsi yang jarang disebutkan -masm=intelmembuat menggunakan -Suntuk memeriksa output perakitan jauh lebih baik.

Sintaks perakitan AT&T terlalu menyakitkan bagi saya.


2
Perbedaan antara AT&T dan Intel bagi saya adalah perbedaan antara C # dan Java. Hanya sintaks. Keduanya mengerikan. :)
Matt Joiner

2
+1 @michael untuk membuat gcc menggunakan sintaks intel alih-alih dewa mengerikan di & t. Memeriksa perakitan menggunakan cukup siklus otak - tidak perlu membuang siklus otak yang src berjalan sebelum dest di opcodes. Sekarang jika hanya gcc yang mendukung __asm ​​{} sebaris seperti kompiler lain, kita semua sudah siap!
greatwolf

10

Makefile saya biasanya berisi

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

Yang paling penting dari opsi-opsi ini telah dibahas sebelumnya, jadi saya akan menunjukkan dua fitur yang belum ditunjukkan:

Meskipun saya sedang bekerja pada basis kode yang perlu C polos untuk portabilitas ke beberapa platform yang masih tidak memiliki kompiler C ++ yang layak, saya melakukan kompilasi "ekstra" dengan kompiler C ++ (selain kompiler C). Itu memiliki 3 manfaat:

  1. kompiler C ++ terkadang memberi saya pesan peringatan yang lebih baik daripada kompiler C.
  2. Kompiler C ++ menerima opsi -Weffc ++, yang kadang-kadang memberi saya beberapa tips yang berguna, yang akan saya lewatkan jika saya hanya mengkompilasinya dalam bahasa C.
  3. Saya dapat menjaga kode relatif mudah untuk port ke C ++, menghindari beberapa syarat batas di mana kode C biasa tidak valid kode C ++ (seperti mendefinisikan variabel bernama "bool").

Ya, saya seorang Pollyanna yang sangat optimis yang terus berpikir bahwa pasti setiap bulan sekarang bahwa satu platform akan dinyatakan usang, atau mendapatkan kompiler C ++ yang layak, dan kami akhirnya dapat beralih ke C ++. Dalam pikiran saya, itu tidak bisa dihindari - satu-satunya pertanyaan adalah apakah itu terjadi sebelum atau setelah manajemen akhirnya mengeluarkan semua kuda. :-)


Poin yang bagus dengan menuliskannya sebagai C ++, saya sering mempertimbangkan ini. (subset secara alami)
Matt Joiner

6
Saya harus menunjukkan bahwa C yang ditinggalkan demi C ++ tidak akan pernah terjadi, maaf :)
Matt Joiner

4
pertimbangkan -o / dev / null bukan rm -f sampah
ulidtko

9
-Wstrict-prototypes -Wmissing-prototypes

10
Dan -Wold-style-definitionjika Anda harus berurusan dengan residivis yang berpikir fungsi gaya K&R adalah ide yang baik, bahkan dengan deklarasi prototipe. (Saya harus berurusan dengan orang-orang seperti itu. Ini benar-benar mengganggu saya ketika saya menemukan kode baru yang ditulis dalam K&R. Cukup buruk memiliki barang-barang K&R lama yang tidak diperbaiki, tetapi kode baru! Grump !!!)
Jonathan Leffler

9

Ini bendera yang bagus yang belum disebutkan:

-Werror-implicit-function-declaration

Berikan kesalahan setiap kali fungsi digunakan sebelum dideklarasikan.


8
man gcc

Manual ini penuh dengan bendera yang menarik dengan deskripsi yang baik. Namun, -Wall mungkin akan membuat gcc setepat mungkin. Jika Anda ingin data yang lebih menarik, Anda harus melihat valgrind atau alat lain untuk memeriksa kesalahan.


1
Itu looooooooooooooooooooooooooooooong, meskipun. man gcc | nlmelaporkan lebih dari 11000 baris. Itu lebih dari halaman terkenal bash!
new123456

12
Syukurlah mereka menjejalkannya ke halaman manual, alih-alih salah satu halaman "info" yang luar biasa tidak masuk akal itu.
Matt Joiner

6

Nah, -Wextraharus standar juga. -Werrormengubah peringatan menjadi kesalahan (yang bisa sangat menjengkelkan, terutama jika Anda kompilasi tanpa -Wno-unused-result). -pedanticdalam kombinasi dengan std=c89memberi Anda peringatan tambahan jika Anda menggunakan fitur C99.

Tapi itu saja. Anda tidak dapat menyetel kompiler C menjadi sesuatu yang lebih bertipe save daripada C sendiri.


6

-M* keluarga pilihan.

Ini memungkinkan Anda menulis membuat file yang secara otomatis mencari tahu file header mana c atau c ++ sumber file Anda. GCC akan menghasilkan file make dengan informasi dependensi ini, dan kemudian Anda menyertakannya dari file make primer Anda.

Berikut adalah contoh makefile yang sangat umum menggunakan -MD dan -MP yang akan mengkompilasi direktori yang penuh dengan c ++ source dan file header, dan mencari tahu semua dependensi secara otomatis:

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

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

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

Berikut adalah posting blog yang membahasnya secara lebih mendalam: http://www.microhowto.info/howto/automatically_generate_makefile_dependencies.html


6

Ada -Werror, yang memperlakukan semua peringatan sebagai kesalahan dan menghentikan kompilasi. The gcchalaman pengguna menjelaskan setiap baris perintah saklar untuk compiler Anda.


@Matt Joiner: Karena Anda tidak menyebutkan arsitektur mesin mana yang Anda gunakan, gccbendera mungkin berbeda antara Anda dan tautan apa pun yang mungkin disarankan siapa pun. Inilah sebabnya mengapa halaman manual disediakan dengan perangkat lunak Anda.
Greg Hewgill

4

-Wfloat-equal

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

Salah satu peringatan baru yang saya suka adalah -Wfloat-equal. Yang satu itu memperingatkan kapan pun Anda [memiliki] angka floating-point dalam kondisi kesetaraan. Itu brilian! Jika Anda memiliki setiap grafik komputer yang diprogram atau (lebih buruk :) algoritma geometri komputasi, Anda tahu bahwa tidak ada dua pelampung yang cocok dengan persamaan ...


10
Mengapung saya lakukan sesuai dengan kesetaraan, yang saya tahu apa yang saya lakukan.
Roland Illig

4

Saya menemukan utas ini mencari bendera untuk memperbaiki masalah tertentu, saya tidak melihatnya di sini jadi saya akan menambahkannya yang hanya membuat saya bingung pada posting saya :

The -Wformat=2flag

-Wformat=> Periksa panggilan ke printfdan scanf, dll., Untuk memastikan bahwa argumen yang diberikan memiliki jenis yang sesuai dengan format string yang ditentukan ...

Dan bagian yang sangat penting tentang itu ( menurut manual GCC ):

-Wformattermasuk dalam -Wall. Untuk kontrol lebih atas beberapa aspek format memeriksa, pilihan -Wformat-y2k, -Wno-format-extra-args, -Wno-format-zero-length, -Wformat-nonliteral, -Wformat-security, dan -Wformat=2yang tersedia, tetapi tidak termasuk dalam -Wall.`

Jadi, hanya karena Anda memilikinya -Wallbukan berarti Anda memiliki semuanya. ;)


3

Saya terkadang menggunakan -suntuk executable yang jauh lebih kecil:

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

Sumber: http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options


6
Anda hanya harus menjalankan stripbiner Anda, dengan cara ini Anda dapat memiliki biner dengan informasi debug, hapus nanti untuk distribusi.
Hasturkun

Ya, stripbekerja juga tetapi -sbisa lebih cepat dan lebih mudah, meskipun itu tidak rumit seperti berlaristrip
Vasiliy Sharapov

3

Meskipun jawaban ini mungkin sedikit di luar topik dan pertanyaannya adalah +1 yang berharga dari saya, sejak itu

Saya sangat tertarik dengan peringatan tambahan, dan / atau mengubah peringatan menjadi kesalahan dalam beberapa kasus untuk benar-benar meminimalkan ketidakcocokan jenis yang tidak disengaja.
ada alat yang harus menangkap SEMUA kesalahan dan potensi kesalahan yang mungkin tidak jelas, ada belat yang IMHO melakukan pekerjaan yang lebih baik dalam menangkap kesalahan dibandingkan dengan gcc atau kompiler lain dalam hal ini. Itu adalah alat yang layak untuk dimiliki di dada-alat Anda.

Pemeriksaan statis melalui alat jenis serat seperti belat, seharusnya menjadi bagian dari rantai alat penyusun.


Itu selalu menunjukkan kesalahan tidak dapat mengajukan file preprosesor di C: \ termasuk, saya tidak yakin apa yang harus dilakukan
Suraj Jain

2

Saya sangat tertarik dengan peringatan tambahan,

Selain itu -Wall, opsi -Watau -Wextra( -Wberfungsi dengan versi gcc yang lebih lama dan yang lebih baru; versi yang lebih baru mendukung nama alternatif -Wextra, yang artinya sama, tetapi lebih deskriptif) memungkinkan berbagai peringatan tambahan.

Bahkan ada lebih banyak peringatan yang tidak diaktifkan oleh salah satu dari mereka, umumnya untuk hal-hal yang lebih buruk dipertanyakan. Set pilihan yang tersedia tergantung pada versi gcc yang Anda gunakan - berkonsultasi man gccatau info gccuntuk detail, atau lihat dokumentasi online untuk versi gcc tertentu yang Anda minati. Dan -pedanticmengeluarkan semua peringatan yang diperlukan oleh standar tertentu yang digunakan (yang tergantung pada opsi lain seperti -std=xxxatau -ansi) dan mengeluh tentang penggunaan ekstensi gcc.

dan / atau mengubah peringatan menjadi kesalahan dalam beberapa kasus untuk benar-benar meminimalkan ketidakcocokan jenis yang tidak disengaja.

-Werrormengubah semua peringatan menjadi kesalahan. Saya tidak berpikir gcc memungkinkan Anda melakukan itu secara selektif untuk peringatan tertentu.

Anda mungkin akan menemukan bahwa Anda harus selektif tentang peringatan mana yang diaktifkan berdasarkan per proyek (terutama jika Anda menggunakan -Werror), karena file header dari perpustakaan eksternal dapat membuat trip beberapa dari mereka. ( -pedantickhususnya cenderung tidak membantu dalam hal ini, dalam pengalaman saya.)


4
"Tapi kurasa gcc tidak membiarkanmu melakukan itu secara selektif untuk peringatan tertentu." Sebenarnya, Anda bisa dengan -Werror=some-warning.
Matthew Flaschen

0
  • -Wmissing-prototypes: Jika fungsi global didefinisikan tanpa deklarasi prototipe sebelumnya.
  • -Wformat-security: Memperingatkan penggunaan fungsi format yang mewakili kemungkinan masalah keamanan. Saat ini, ini memperingatkan tentang panggilan ke printfdan scanffungsi di mana string format bukan string literal dan tidak ada argumen format

0
  • -Werror=return-type: Menerapkan kesalahan saat fungsi tidak kembali di gcc. Itu /we4716di Visual Studio.

  • -Werror=implicit-function-declaration: Menerapkan kesalahan saat fungsi digunakan tanpa didefinisikan / tidak disertakan. Itu /we4013di Visual Studio.

  • -Werror=incompatible-pointer-types: Selesaikan kesalahan saat tipe pointer tidak cocok dengan tipe pointer yang diharapkan. Itu /we4133di Visual Studio.

Sebenarnya, saya ingin menyimpan kode-C lintas-platform, dan saya menggunakan CMake, dan saya memasukkan cflag yang disediakan ke dalam CMakeLists.txt seperti:

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()
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.