Mengapa saya harus selalu mengaktifkan peringatan kompiler?

302

Saya sering mendengar bahwa ketika mengkompilasi program C dan C ++ saya harus "selalu mengaktifkan peringatan kompiler". Mengapa ini perlu? Bagaimana aku melakukan itu?

Terkadang saya juga mendengar bahwa saya harus "memperlakukan peringatan sebagai kesalahan". Haruskah saya? Bagaimana aku melakukan itu?

n. 'kata ganti' m.
sumber

Jawaban:

341

Mengapa mengaktifkan peringatan?

Kompiler C dan C ++ terkenal buruk dalam melaporkan beberapa kesalahan umum programmer secara default , seperti:

  • lupa menginisialisasi variabel
  • lupa returnnilai dari suatu fungsi
  • argumen di printfdan scanfkeluarga tidak cocok dengan string format
  • suatu fungsi digunakan tanpa dideklarasikan sebelumnya (hanya C)

Ini dapat dideteksi dan dilaporkan, biasanya tidak secara default; fitur ini harus secara eksplisit diminta melalui opsi kompiler.

Bagaimana cara mengaktifkan peringatan?

Ini tergantung pada kompiler Anda.

Microsoft C dan C ++ compiler memahami switch seperti /W1, /W2, /W3, /W4dan /Wall. Gunakan setidaknya /W3. /W4dan /Wallmungkin memancarkan peringatan palsu untuk file header sistem, tetapi jika proyek Anda dikompilasi dengan bersih dengan salah satu opsi ini, lakukan. Opsi-opsi ini saling eksklusif.

Kebanyakan kompiler lain memahami opsi seperti -Wall, -Wpedanticdan -Wextra. -Wallsangat penting dan sisanya direkomendasikan (perhatikan bahwa, terlepas dari namanya, -Wallhanya memungkinkan peringatan yang paling penting, tidak semuanya ). Opsi-opsi ini dapat digunakan secara terpisah atau bersama-sama.

IDE Anda mungkin memiliki cara untuk mengaktifkannya dari antarmuka pengguna.

Mengapa memperlakukan peringatan sebagai kesalahan? Itu hanya peringatan!

Peringatan kompiler menandakan masalah yang berpotensi serius dalam kode Anda. Masalah-masalah yang tercantum di atas hampir selalu berakibat fatal; orang lain mungkin atau mungkin tidak, tetapi Anda ingin kompilasi gagal meskipun ternyata alarm palsu. Selidiki setiap peringatan, temukan akar masalahnya, dan perbaiki. Jika alarm palsu, atasi - yaitu, gunakan fitur atau konstruksi bahasa yang berbeda sehingga peringatan tidak lagi terpicu. Jika ini terbukti sangat sulit, nonaktifkan peringatan tersebut berdasarkan kasus per kasus.

Anda tidak ingin hanya meninggalkan peringatan sebagai peringatan meskipun semua itu adalah alarm palsu. Bisa saja OK untuk proyek yang sangat kecil di mana jumlah total peringatan yang dikeluarkan kurang dari 7. Ada yang lebih, dan mudah untuk peringatan baru hilang dalam banjir yang sudah dikenal lama. Jangan biarkan itu terjadi. Hanya menyebabkan semua proyek Anda dikompilasi dengan bersih.

Catatan ini berlaku untuk pengembangan program. Jika Anda merilis proyek Anda ke dunia dalam bentuk sumber, maka mungkin ide yang baik untuk tidak memasok -Werroratau setara dalam skrip build yang dirilis . Orang-orang mungkin mencoba membangun proyek Anda dengan versi kompiler yang berbeda, atau dengan kompiler yang berbeda secara bersamaan, yang mungkin memiliki serangkaian peringatan yang berbeda yang diaktifkan. Anda mungkin ingin bangunan mereka berhasil. Itu masih merupakan ide yang baik untuk tetap mengaktifkan peringatan, sehingga orang yang melihat pesan peringatan dapat mengirimkan laporan bug atau patch kepada Anda.

Bagaimana memperlakukan peringatan sebagai kesalahan?

Sekali lagi ini dilakukan dengan sakelar kompiler. /WXuntuk Microsoft, kebanyakan digunakan orang lain -Werror. Dalam kedua kasus tersebut, kompilasi akan gagal jika ada peringatan yang dihasilkan.

n. 'kata ganti' m.
sumber
107
Saya telah memposting tanya jawab ini karena saya muak dan lelah memberi tahu orang-orang untuk mengaktifkan peringatan. Sekarang saya bisa mengarahkan mereka ke sini (atau, jika saya dalam suasana hati yang jahat, tutup pertanyaan mereka sebagai penipu). Anda dipersilakan untuk meningkatkan jawaban ini atau menambahkan jawaban Anda!
n. 'kata ganti' m.
16
Anda juga dapat menggunakan dentang ini -Weverything
PMG
9
Satu-satunya pengubah yang saya tambahkan adalah bahwa beberapa peringatan mungkin tidak membantu untuk aplikasi Anda. (Saya telah melihat peringatan bahwa kompiler menambahkan 2 byte padding antar elemen dalam sebuah struct. Aplikasi ini untuk prototyping, jadi sedikit memori yang terbuang tidak mengganggu kita.) Perlakukan semua peringatan sebagai kesalahan dan kemudian hanya menonaktifkan peringatan jika Anda tahu mengapa peringatan itu tidak akan membantu Anda.
Kyle A
20
Kelemahan dari memperlakukan peringatan sebagai kesalahan bagi orang-orang yang mengikuti instruksi pembuatan default Anda adalah bahwa kode Anda membusuk saat kompiler menambah peringatan baru. Pengguna yang mengunduh kode Anda dan mencoba membuatnya di masa depan mungkin tidak dapat melakukannya, karena kompiler mereka terlalu baru dan mengeluarkan peringatan tentang beberapa tanda kurung tambahan atau sesuatu yang tidak dipedulikan kompiler Anda. Pengguna yang menemukan kesalahan tidak bertanggung jawab atas kode Anda atau sistem build Anda, dan tidak tahu cara mematikan memperlakukan peringatan sebagai kesalahan dan benar-benar membangun proyek Anda.
memotong
15
@ sempurna Ya, ini terjadi pada saya beberapa kali. Bukan masalah besar. Jika Anda memilih untuk membangun perangkat lunak yang tidak terawat menggunakan kompiler yang tidak pernah diuji, yah, Anda lebih baik bersiap untuk melakukan pemeliharaan sendiri.
n. 'kata ganti' m.
94

C, yang terkenal, adalah bahasa tingkat rendah seperti HLL. C ++, meskipun sepertinya bahasa tingkat jauh lebih tinggi dari C, masih memiliki beberapa sifat. Dan salah satu dari sifat-sifat itu adalah bahwa bahasa dirancang oleh programmer, untuk programmer - dan, khususnya, programmer yang tahu apa yang mereka lakukan.

[Untuk sisa jawaban ini saya akan fokus pada C. Sebagian besar dari apa yang akan saya katakan juga berlaku untuk C ++, meskipun mungkin tidak sekuat itu. Meskipun seperti yang dikatakan Bjarne Stroustrup dengan terkenal, "C membuatnya mudah untuk menembak diri sendiri di kaki; C ++ membuatnya lebih sulit, tetapi ketika Anda melakukannya, itu akan menghancurkan seluruh kaki Anda." ]

Jika Anda tahu apa yang Anda lakukan - benar - benar tahu apa yang Anda lakukan - kadang-kadang Anda mungkin harus "melanggar aturan". Tapi sebagian besar waktu, sebagian besar dari kita akan setuju bahwa aturan yang bermaksud baik membuat kita semua dari masalah, dan yang melanggar aturan itu sepanjang waktu adalah ide yang buruk.

Tetapi dalam C dan C ++, ada sejumlah besar hal yang dapat Anda lakukan yang merupakan "ide buruk" tetapi tidak secara formal "melanggar aturan". Kadang-kadang mereka adalah ide yang buruk beberapa waktu (tetapi mungkin bisa dipertahankan kali lain); terkadang mereka adalah ide yang buruk hampir sepanjang waktu. Tetapi tradisi selalu tidak memperingatkan tentang hal-hal ini - karena, sekali lagi, asumsi adalah bahwa programmer tahu apa yang mereka lakukan, mereka tidak akan melakukan hal-hal ini tanpa alasan yang baik, mereka akan terganggu oleh banyak peringatan yang tidak perlu.

Tetapi tentu saja tidak semua programmer benar - benar tahu apa yang mereka lakukan. Dan, khususnya, setiap programmer C (tidak peduli seberapa berpengalaman) melewati fase menjadi programmer C awal. Dan bahkan pemrogram C yang berpengalaman bisa ceroboh dan membuat kesalahan.

Akhirnya, pengalaman tidak hanya menunjukkan bahwa pemrogram melakukan kesalahan, tetapi bahwa kesalahan ini dapat memiliki konsekuensi nyata dan serius. Jika Anda membuat kesalahan, dan kompiler tidak memperingatkan Anda tentang hal itu, dan entah bagaimana program tidak segera crash atau melakukan sesuatu yang jelas salah karena kesalahan itu, kesalahan tersebut dapat bersembunyi di sana, disembunyikan, kadang-kadang selama bertahun-tahun, hingga menyebabkan masalah yang sangat besar.

Jadi ternyata, pada umumnya, peringatan adalah ide yang bagus. Bahkan pemrogram berpengalaman telah belajar (sebenarnya, " terutama pemrogram berpengalaman telah belajar") bahwa, secara seimbang, peringatan cenderung lebih baik daripada merugikan. Untuk setiap kali Anda melakukan kesalahan dengan sengaja dan peringatan itu mengganggu, mungkin ada setidaknya sepuluh kali Anda melakukan kesalahan karena kecelakaan dan peringatan itu menyelamatkan Anda dari masalah lebih lanjut. Dan sebagian besar peringatan dapat dinonaktifkan atau dikerjakan untuk beberapa saat ketika Anda benar-benar ingin melakukan hal yang "salah".

(Sebuah contoh klasik dari suatu "kesalahan" adalah tes if(a = b)Sebagian besar waktu, ini adalah kesalahan, sehingga sebagian besar kompiler hari ini memperingatkan tentang hal itu -.. Beberapa bahkan secara default Tetapi jika Anda benar-benar ingin baik assign bke adan uji hasilnya, Anda dapat menonaktifkan peringatan dengan mengetik if((a = b)).)

Pertanyaan kedua adalah, mengapa Anda ingin meminta kompiler untuk memperlakukan peringatan sebagai kesalahan? Saya akan mengatakan itu karena sifat manusia, khususnya, reaksi yang terlalu mudah untuk mengatakan "Oh, itu hanya peringatan, itu tidak begitu penting, saya akan membersihkannya nanti." Tetapi jika Anda suka menunda-nunda (dan saya tidak tahu tentang Anda, tapi saya suka menunda - nunda) mudah untuk menunda pembersihan pada dasarnya - dan jika Anda terbiasa mengabaikan peringatan, itu semakin mudah dan lebih mudah untuk melewatkan pesan peringatan penting yang ada di sana, tanpa disadari, di tengah semua yang Anda abaikan.

Jadi meminta kompiler untuk memperlakukan peringatan karena kesalahan adalah trik kecil yang bisa Anda mainkan sendiri untuk mengatasi kelemahan manusia ini.

Secara pribadi, saya tidak berkeras memperlakukan peringatan sebagai kesalahan. (Sebenarnya, jika saya jujur, saya dapat mengatakan bahwa saya hampir tidak pernah mengaktifkan opsi itu dalam pemrograman "pribadi" saya.) Tetapi Anda dapat yakin bahwa saya mengaktifkan opsi itu di tempat kerja, di mana panduan gaya kami (yang saya panduankan) menulis) mengamanatkan penggunaannya. Dan saya akan mengatakan - saya menduga sebagian besar programmer profesional akan mengatakan - bahwa setiap toko yang tidak memperlakukan peringatan karena kesalahan dalam C berperilaku tidak bertanggung jawab, tidak mematuhi praktik terbaik industri yang diterima secara umum.

Steve Summit
sumber
9
"programmer yang tahu apa yang mereka lakukan" - LOL; ada fallacy "no true Scotsman" jika saya pernah melihatnya :)
Dancrumb
3
@ Dancrumb LOL kembali atcha. Saya tidak pernah benar-benar yakin bahwa saya memahami kekeliruan orang Skotlandia sejati , tetapi saya menyukainya, jadi ini akan menjadi latihan yang baik untuk saya. Saya kira aplikasi di sini seperti ini: "Tidak ada programmer C yang akan menulis if(a = b), oleh karena itu kita tidak perlu memperingatkan tentang hal itu." (Kemudian seseorang menghasilkan daftar 10 bug kritis dalam 10 produk yang dirilis yang dihasilkan dari kesalahan khusus ini.) "Oke, tidak ada programmer C yang berpengalaman yang akan pernah menulis itu ..."
Steve Summit
3
@SteveSummit tetapi seorang programmer C yang benar - benar berpengalaman dapat menulis if (returnCodeFromFoo = foo(bar))dan bersungguh-sungguh, untuk menangkap dan menguji kode di satu tempat (Asumsikan satu - satunya tujuan fooadalah untuk memiliki efek samping!) Fakta bahwa seorang programmer yang benar-benar berpengalaman mungkin tahu ini bukan gaya pengkodean yang bagus adalah intinya;)
alephzero
5
Masalahnya, programmer paling berpengalaman memungkinkan sebagian besar, jika tidak semua, peringatan. Jika mereka ingin menggunakan sesuatu seperti if (returnCodeFromFoo = foo(bar)), maka mereka memberikan komentar dan mematikan peringatan (sehingga ketika programmer pemeliharaan melihatnya 4 tahun kemudian, dia akan menyadari bahwa kode itu disengaja. Karena itu, saya bekerja dengan seseorang yang (dalam Microsoft C ++ land) bersikeras bahwa menggabungkan / Tembok dengan memperlakukan peringatan sebagai kesalahan adalah cara untuk pergi. Eh, itu tidak (kecuali jika Anda ingin memasukkan banyak komentar penindasan)
Flydog57
3
Sebagai seseorang yang tidak menulis kode setiap hari, tetapi ketika saya melakukannya cenderung bare metal (sering di papan desain saya sendiri) saya menemukan peringatan sangat berharga. Ketika memasukkan nilai ke register internal (untuk lokasi deskriptor DMA adalah contoh) peringatan tentang konversi ke penunjuk berarti saya melakukan pemeran untuk menghapus peringatan. Itu tidak akan menjadi kesalahan, tetapi jika orang lain (atau bahkan saya sendiri!) Mengambil kode itu dalam beberapa bulan, itu bisa membingungkan. Selain itu, saya menerapkan aturan tidak ada peringatan untuk output alat CAD saya juga.
Peter Smith
39

Peringatan terdiri dari saran terbaik yang bisa dibuat oleh beberapa pengembang C ++ paling terampil dalam sebuah aplikasi. Mereka layak dijaga.

C ++, sebagai bahasa lengkap Turing, memiliki banyak kasus di mana kompiler hanya harus percaya bahwa Anda tahu apa yang Anda lakukan. Namun, ada banyak kasus di mana kompiler dapat menyadari bahwa Anda mungkin tidak bermaksud untuk menulis apa yang Anda tulis. Contoh klasik adalah kode printf () yang tidak cocok dengan argumen, atau std :: strings dilewatkan ke printf (bukan yang pernah terjadi pada saya!). Dalam kasus ini, kode yang Anda tulis bukan kesalahan. Ini adalah ekspresi C ++ yang valid dengan interpretasi yang valid untuk ditindaklanjuti oleh kompiler. Tetapi kompiler memiliki firasat yang kuat bahwa Anda hanya mengabaikan sesuatu yang mudah dideteksi oleh kompiler modern. Ini adalah peringatan. Mereka adalah hal-hal yang jelas bagi kompiler, menggunakan semua aturan ketat C ++ yang dapat digunakannya, yang mungkin Anda abaikan.

Menonaktifkan peringatan, atau mengabaikannya, seperti memilih untuk mengabaikan saran gratis dari mereka yang lebih terampil daripada Anda. Ini adalah pelajaran dalam huberis yang berakhir ketika Anda terbang terlalu dekat dengan matahari dan sayap Anda meleleh, atau kesalahan memori kerusakan terjadi. Di antara keduanya, aku akan jatuh dari langit kapan saja!

"Perlakukan peringatan sebagai kesalahan" adalah versi ekstrem dari filosofi ini. Idenya di sini adalah bahwa Anda menyelesaikan setiap peringatan yang diberikan kompiler kepada Anda - Anda mendengarkan setiap nasihat gratis dan menindaklanjutinya. Apakah ini model yang baik untuk pengembangan untuk Anda tergantung pada tim dan produk apa yang sedang Anda kerjakan. Ini adalah pendekatan pertapaan yang mungkin dimiliki seorang bhikkhu. Bagi sebagian orang, ini bekerja dengan baik. Bagi yang lain, tidak.

Pada banyak aplikasi saya, kami tidak memperlakukan peringatan sebagai kesalahan. Kami melakukan ini karena aplikasi khusus ini perlu dikompilasi pada beberapa platform dengan beberapa kompiler dari berbagai usia. Terkadang kami menemukan bahwa sebenarnya tidak mungkin untuk memperbaiki peringatan di satu sisi tanpa mengubahnya menjadi peringatan di platform lain. Jadi kami hanya berhati-hati. Kami menghormati peringatan, tetapi kami tidak membungkuk untuk itu.

Cort Ammon
sumber
11
Apa yang harus dilakukan oleh C ++ sebagai Turing lengkap untuk itu. Banyak bahasa yang lengkap dan tidak mempercayai Anda jika Anda melakukan sesuatu yang salah ....
Selamat tinggal
3
@KamiKaze setiap bahasa akan memiliki kesalahan idiomatik (mis. Java tidak dapat menghentikan Anda menulis yang tidak konsisten equals/ hashCode), dan ini adalah kualitas masalah implementasi yang dilaporkan.
Caleth
2
@KamiKaze Bit kelengkapan Turing muncul untuk menunjukkan bahwa ada kasus di mana kompiler tidak dapat membuktikan bahwa kode Anda akan gagal berfungsi sesuai rencana. Ini penting karena kompiler tidak dapat membuat kode "salah" salah. Kesalahan hanya dapat dicadangkan untuk perilaku yang pasti oleh perancang bahasa akan selalu "salah." (biasanya karena mengarah ke jalan yang tidak konsisten).
Cort Ammon
2
Yang juga menunjuk pada tantangan dengan "semua peringatan adalah kesalahan." Peringatan, secara desain, lebih oportunistik, memicu beberapa kode yang berpotensi benar sebagai imbalan karena memicu lebih sering pada kode yang salah. Peringatan karena kesalahan menyebabkan Anda tidak bisa menggunakan kemampuan bahasa lengkap.
Cort Ammon
2
Namun, secara umum, programmer menginginkan bahasa yang lebih dari sekadar "aman". Kami ingin bahasa yang melakukan hal yang kami pikir kami harus lakukan. Dengan demikian, peringatan tetap penting karena kelas sebenarnya dari hal-hal yang kita inginkan dari komputer adalah kelas semantik. Kompilator dapat mengambilnya dengan mendefinisikan "salah" atau "tidak aman," tetapi pada akhirnya Anda masih memiliki superclass dari perilaku yang diinginkan oleh programer. Peringatan membantu mempersempit superclass ke bawah.
Cort Ammon
19

Tidak hanya menangani peringatan membuat kode lebih baik, itu membuat Anda seorang programmer yang lebih baik. Peringatan akan memberi tahu Anda tentang hal-hal yang mungkin tampak sedikit bagi Anda hari ini, tetapi suatu hari kebiasaan buruk itu akan kembali dan menggigit kepalamu.

Gunakan tipe yang benar, kembalikan nilai itu, evaluasi kembali nilai itu. Luangkan waktu dan renungkan "Apakah ini benar-benar tipe yang tepat dalam konteks ini?" "Apakah saya perlu mengembalikan ini?" Dan masalah besar; "Apakah kode ini akan portabel untuk 10 tahun ke depan?"

Biasakan menulis kode bebas peringatan di tempat pertama.

RedSonja
sumber
17

Jawaban lainnya sangat bagus dan saya tidak ingin mengulangi apa yang mereka katakan.

Satu aspek lain untuk "mengapa mengaktifkan peringatan" yang belum disentuh dengan benar adalah bahwa mereka sangat membantu dalam pemeliharaan kode. Ketika Anda menulis sebuah program dengan ukuran yang signifikan, menjadi tidak mungkin untuk menyimpan semuanya di kepala Anda sekaligus. Anda biasanya memiliki satu atau tiga fungsi yang secara aktif Anda tulis dan pikirkan, dan mungkin satu atau tiga file di layar yang dapat Anda rujuk, tetapi sebagian besar program ada di latar belakang di suatu tempat dan Anda harus percaya bahwa itu terus bekerja.

Memiliki peringatan, dan membuatnya seenergi dan di wajah Anda mungkin, membantu mengingatkan Anda jika sesuatu yang Anda ubah membuat masalah untuk sesuatu yang tidak dapat Anda lihat.

Ambil contoh, peringatan dentang -Wswitch-enum. Itu memicu peringatan jika Anda menggunakan sakelar pada enum dan melewatkan salah satu nilai enum yang mungkin. Ini adalah sesuatu yang Anda mungkin berpikir untuk membuat kesalahan: Anda mungkin setidaknya melihat daftar nilai enum ketika Anda menulis pernyataan switch. Anda bahkan mungkin memiliki IDE yang menghasilkan opsi sakelar untuk Anda, tanpa meninggalkan ruang untuk kesalahan manusia.

Peringatan ini benar-benar muncul ketika, enam bulan kemudian Anda menambahkan entri lain yang mungkin ke enum. Sekali lagi, jika Anda berpikir tentang kode yang dimaksud, Anda mungkin akan baik-baik saja. Tetapi jika enum ini digunakan untuk berbagai tujuan yang berbeda dan ini untuk salah satu yang Anda butuhkan opsi tambahan, sangat mudah untuk lupa memperbarui sakelar dalam file yang belum Anda sentuh selama 6 bulan.

Anda dapat memikirkan peringatan dengan cara yang sama seperti yang Anda pikirkan tentang kasus uji otomatis: mereka membantu Anda memastikan bahwa kode masuk akal dan melakukan apa yang Anda butuhkan saat pertama kali menulisnya, tetapi mereka membantu lebih banyak lagi untuk memastikannya terus melakukan apa yang Anda butuhkan saat Anda mendorongnya. Perbedaannya adalah bahwa test case bekerja sangat sempit dengan persyaratan kode Anda dan Anda harus menulisnya, sementara peringatan bekerja secara luas untuk standar yang masuk akal untuk hampir semua kode, dan mereka sangat murah hati disediakan oleh para peti mati yang membuat kompiler.

Josiah
sumber
9
Cara lain mereka membantu dalam pemeliharaan adalah ketika Anda melihat kode orang lain dan tidak bisa memastikan apakah efek sampingnya disengaja. Dengan peringatan aktif, Anda tahu mereka setidaknya mengetahui masalah ini.
Robin Bennett
Atau dalam kasus saya, Anda mengimpor file dari sistem tertanam yang berisi pernyataan saklar baris 3000+ atas enum dengan beberapa ribu nilai. Peringatan "jatuh melalui" (dihindari dengan menggunakan goto) menutupi sejumlah bug "tidak ditangani" ... kompiler yang disematkan tidak memancarkan salah satu dari itu, tetapi bug itu tetap penting.
Móż
15

Peringatan tidak tetap akan , cepat atau lambat, akan menyebabkan kesalahan dalam kode Anda .


Debugging kesalahan segmentasi, misalnya, mengharuskan programmer untuk melacak root (penyebab) kesalahan, yang biasanya terletak di tempat sebelumnya dalam kode Anda daripada garis yang akhirnya menyebabkan kesalahan segmentasi.

Ini sangat tipikal bahwa penyebabnya adalah garis di mana kompiler mengeluarkan peringatan yang Anda abaikan, dan garis yang menyebabkan segmentasi kesalahan garis yang akhirnya menyebabkan kesalahan.

Memperbaiki peringatan mengarah ke memperbaiki masalah .. Klasik!

Peragaan di atas .. Pertimbangkan kode berikut:

#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;
}

yang ketika dikompilasi dengan bendera "Wextra" yang diteruskan ke GCC, memberikan:

main.c: In function 'main':
main.c:9:21: warning: 'idx' is used uninitialized in this function [-Wuninitialized]
    9 |   printf("%c\n", str[idx]);
      |                     ^

yang bisa saya abaikan dan laksanakan kodenya .. Dan kemudian saya akan menyaksikan kesalahan segmentasi "grand", seperti yang dikatakan oleh profesor epicurus IP saya:

Kesalahan segmentasi

Untuk men-debug ini dalam skenario dunia nyata, orang akan mulai dari garis yang menyebabkan kesalahan segmentasi dan mencoba melacak apa akar penyebabnya. Mereka harus mencari apa yang telah terjadi idan strdi dalam jumlah yang sangat besar itu kode di sana ...

Hingga, suatu hari, mereka menemukan diri mereka dalam situasi di mana mereka menemukan yang idxdigunakan tidak diinisialisasi, sehingga memiliki nilai sampah, yang menghasilkan pengindeksan string (cara) di luar batasnya, yang mengarah ke kesalahan segmentasi.

Kalau saja mereka tidak mengabaikan peringatan itu, mereka akan segera menemukan bug!

gsamaras
sumber
4
Untuk judul Anda: belum tentu. Misalnya, peringatan yang menyarankan untuk menggunakan tanda kurung dalam formula yang benar-benar tidak membutuhkannya menunjuk ke non-masalah yang tidak akan pernah menyebabkan kesalahan. Prioritas operator dalam bahasa pemrograman yang diberikan tidak berubah. Pernah.
Marc van Leeuwen
4
@MarcvanLeeuwen Contoh yang Anda kutip dapat berubah menjadi kesalahan, misalnya jika programmer yang tidak ingat operator diutamakan dengan benar mengubah rumus sedikit. Peringatan itu memberi tahu Anda: "itu mungkin tidak jelas bagi seseorang di beberapa titik, tambahkan beberapa tanda kurung untuk membuatnya lebih jelas". Meskipun orang harus setuju bahwa judul posting asli tidak selalu benar.
Hubert Jasieniecki
^ Apa pun bisa diubah menjadi kesalahan. Sama mudahnya untuk memperkenalkan bug ke dalam kode yang di-kurung sebagian sebagai ke dalam kode yang di dalam kurung sepenuhnya.
Jim Balter
... Sebagai tambahan, saya punya pertanyaan untuk debugger yang reaksi pertamanya terhadap "Oh, itu segfault dari str[idx]" bukan "Oke, di mana strdan idxditentukan?`
Justin Time - Reinstate Monica
2
Anda beruntung jika mendapatkan kesalahan segmentasi. Jika Anda kurang beruntung, Anda mungkin kebetulan idxadalah nilai yang Anda harapkan pada tes Anda (tidak terlalu tidak mungkin jika nilai yang diharapkan adalah 0), dan sebenarnya menunjuk pada beberapa data sensitif yang tidak boleh dicetak saat digunakan.
celtschk
14

Memperlakukan peringatan sebagai kesalahan hanyalah cara disiplin diri: Anda menyusun program untuk menguji fitur baru yang mengkilap itu, tetapi Anda tidak bisa sampai memperbaiki bagian yang ceroboh. Tidak ada informasi tambahan yang Werrordisediakan, itu hanya menetapkan prioritas dengan sangat jelas:

Jangan tambahkan kode baru sampai Anda memperbaiki masalah dalam kode yang ada

Benar-benar pola pikir yang penting, bukan alat. Keluaran diagnostik kompiler adalah alat. MISRA (untuk embedded C) adalah alat lain. Tidak masalah yang mana yang Anda gunakan, tetapi bisa dibilang peringatan kompiler adalah alat termudah yang bisa Anda dapatkan (hanya satu bendera untuk ditetapkan) dan rasio sinyal terhadap noise sangat tinggi. Jadi tidak ada alasan untuk tidak menggunakannya.

Tidak ada alat yang sempurna. Jika Anda menulis const float pi = 3.14;, sebagian besar alat tidak akan memberi tahu Anda bahwa Anda mendefinisikan π dengan presisi buruk yang dapat menyebabkan masalah di kemudian hari. Sebagian besar alat tidak akan menaikkan alis if(tmp < 42), bahkan jika sudah umum diketahui bahwa memberikan variabel nama yang tidak berarti dan menggunakan angka ajaib adalah cara untuk bencana dalam proyek-proyek besar. Anda harus memahami bahwa kode "tes cepat" apa pun yang Anda tulis hanyalah: tes, dan Anda harus menyelesaikannya sebelum melanjutkan ke tugas lain, sementara Anda masih melihat kekurangannya. Jika Anda membiarkan kode seperti itu, men-debug jika setelah Anda menghabiskan dua bulan menambahkan fitur baru akan jauh lebih sulit.

Setelah Anda masuk ke pola pikir yang benar, tidak ada gunanya menggunakan Werror. Memiliki peringatan sebagai peringatan akan memungkinkan Anda mengambil keputusan berdasarkan informasi apakah masih masuk akal untuk menjalankan sesi debug yang akan Anda mulai, atau membatalkannya dan memperbaiki peringatan terlebih dahulu.

Dmitry Grigoryev
sumber
3
Lebih baik atau lebih buruk, clippyalat linting untuk Rust akan benar-benar memperingatkan tentang konstanta "3.14". Ini sebenarnya contoh dalam dokumen . Tetapi seperti yang mungkin Anda tebak dari namanya, clippybangga menjadi orang yang sangat membantu.
emk
1
@ emk Terima kasih untuk contoh ini, mungkin saya harus mengulangi jawaban saya dengan cara yang tidak pernah mengatakan "tidak pernah" . Saya tidak bermaksud mengatakan bahwa memeriksa nilai imp yang tidak tepat tidak mungkin, hanya dengan menghilangkan peringatan tidak menjamin kualitas kode yang layak.
Dmitry Grigoryev
Satu hal yang diingatkan oleh kesalahan adalah bahwa bangunan otomatis akan gagal, sehingga memberi tahu Anda bahwa ada sesuatu yang salah. Otomatis membangun juga memungkinkan untuk otomatisasi linting (ledakan adalah 3 ... 2 ... 1 .. :)
Móż
8

Sebagai seseorang yang bekerja dengan kode C tertanam lama, mengaktifkan peringatan kompiler telah membantu menunjukkan banyak kelemahan dan bidang untuk diselidiki ketika mengusulkan perbaikan. Dalam gcc memanfaatkan -Walldan -Wextrabahkan -Wshadowtelah menjadi penting. Saya tidak akan menghadapi setiap bahaya, tetapi saya akan membuat daftar beberapa yang muncul yang membantu menunjukkan masalah kode.

Variabel tertinggal

Yang ini dapat dengan mudah menunjukkan pekerjaan yang belum selesai dan area yang mungkin tidak memanfaatkan semua variabel yang lulus yang bisa menjadi masalah. Mari kita lihat fungsi sederhana yang dapat memicu ini:

int foo(int a, int b)
{
   int c = 0;

   if (a > 0)
   {
        return a;
   }
   return 0;
}

Hanya mengkompilasi ini tanpa -Wall atau -Wextra mengembalikan tidak ada masalah. -Wall akan memberi tahu Anda bahwa citu tidak pernah digunakan:

foo.c: Dalam fungsi 'foo':

foo.c: 9: 20: peringatan: variabel yang tidak digunakan 'c' [-Wunused-variable]

-Wextra juga akan memberi tahu Anda bahwa parameter Anda b tidak melakukan apa-apa:

foo.c: Dalam fungsi 'foo':

foo.c: 9: 20: peringatan: variabel yang tidak digunakan 'c' [-Wunused-variable]

foo.c: 7: 20: peringatan: parameter yang tidak digunakan 'b' [-Wunused-parameter] int foo (int a, int b)

Global Variable shadowing

Ini agak sulit dan tidak muncul sampai -Wshadowdigunakan. Mari kita modifikasi contoh di atas untuk menambahkan saja, tetapi kebetulan ada global dengan nama yang sama dengan lokal yang menyebabkan banyak kebingungan ketika mencoba menggunakan keduanya.

int c = 7;

int foo(int a, int b)
{
   int c = a + b;
   return c;
}

Ketika -Wshadow diaktifkan, mudah untuk menemukan masalah ini.

foo.c: 11: 9: peringatan: deklarasi 'c' membayangi deklarasi global [-Wshadow]

foo.c: 1: 5: note: deklarasi shadowed ada di sini

Memformat string

Ini tidak memerlukan flag tambahan apa pun di gcc, tetapi masih menjadi sumber masalah di masa lalu. Fungsi sederhana yang mencoba mencetak data, tetapi memiliki kesalahan pemformatan bisa terlihat seperti ini:

void foo(const char * str)
{
    printf("str = %d\n", str);
}

Ini tidak mencetak string karena bendera pemformatan salah dan gcc dengan senang hati akan memberi tahu Anda ini mungkin bukan yang Anda inginkan:

foo.c: Dalam fungsi 'foo':

foo.c: 10:12: peringatan: format '% d' mengharapkan argumen bertipe 'int', tetapi argumen 2 memiliki tipe 'const char *' [-Wformat =]


Ini hanya tiga dari banyak hal yang dapat diperiksa oleh kompiler untuk Anda. Ada banyak yang lain seperti menggunakan variabel tidak diinisialisasi yang ditunjukkan orang lain.

Dom
sumber
7
Di dunia yang tertanam, peringatan yang paling membuatku khawatir adalah " possible loss of precision" dan " comparison between signed and unsigned" peringatan. Saya merasa sulit untuk memahami berapa banyak "programmer" mengabaikan ini (pada kenyataannya, saya tidak begitu yakin mengapa mereka bukan kesalahan)
Mawg mengatakan mengembalikan Monica
3
Dalam kasus terakhir, @Mawg, saya percaya alasan utama itu bukan kesalahan adalah karena hasil sizeoftidak ditandatangani, tetapi tipe integer standar ditandatangani. The sizeofjenis hasil, size_t, biasanya digunakan untuk apapun yang berhubungan dengan jenis ukuran, seperti, misalnya, keselarasan atau array / count elemen wadah, sedangkan bilangan bulat pada umumnya dimaksudkan untuk digunakan sebagai " intkecuali dinyatakan diperlukan". Mempertimbangkan berapa banyak orang yang diajarkan untuk menggunakannya intuntuk beralih ke wadah mereka (dibandingkan intdengan size_t), menjadikannya sebuah kesalahan akan menghancurkan segalanya. ; P
Justin Time - Kembalikan Monica
6

Ini adalah jawaban spesifik untuk C, dan mengapa ini jauh lebih penting bagi C daripada yang lainnya.

#include <stdio.h>
int main()
{
   FILE *fp = "some string";
}

Kode ini dikompilasi dengan peringatan . Apa yang seharusnya dan seharusnya merupakan kesalahan dalam hampir semua bahasa lain di planet ini (pembatasan bahasa assembly) adalah peringatan dalam C. Peringatan di C hampir selalu merupakan kesalahan dalam penyamaran. Peringatan harus diperbaiki, tidak ditekan.

Dengan gcc, kami melakukan ini sebagai gcc -Wall -Werror.

Ini juga merupakan alasan tingginya ketidaknyamanan tentang beberapa peringatan API MS yang tidak aman. Sebagian besar orang yang memprogram C telah mempelajari cara yang sulit untuk memperlakukan peringatan sebagai kesalahan dan hal-hal ini tampaknya bukan hal yang sama dan menginginkan perbaikan non-portabel.

Joshua
sumber
5

PERINGATAN KOMPILER ADALAH TEMAN ANDA (tidak berteriak, huruf besar untuk penekanan).

Saya bekerja pada sistem warisan Fortran-77. Kompiler memberi tahu saya hal-hal yang berharga: argumen tipe data tidak cocok pada panggilan subrutin, menggunakan variabel lokal sebelum nilai telah ditetapkan ke dalam variabel, jika saya memiliki argumen variabel atau subrutin yang tidak digunakan. Ini hampir selalu merupakan kesalahan.

Menghindari posting lama: Ketika kode saya dikompilasi dengan bersih, 97% itu berfungsi. Orang lain yang bekerja dengan saya mengkompilasi dengan semua peringatan mati, menghabiskan berjam-jam atau berhari-hari di debugger, lalu meminta saya untuk membantu. Saya hanya mengkompilasi kode dengan peringatan menyala dan katakan padanya apa yang harus diperbaiki.

Mark Diaz
sumber
5

Anda harus selalu mengaktifkan peringatan kompiler karena kompilator sering dapat memberi tahu Anda apa yang salah dengan kode Anda. Untuk melakukan ini, Anda beralih -Wall -Wextrake kompiler.

Anda biasanya harus memperlakukan peringatan sebagai kesalahan karena peringatan biasanya menandakan bahwa ada yang salah dengan kode Anda. Namun, seringkali sangat mudah untuk mengabaikan kesalahan ini. Oleh karena itu, memperlakukan mereka sebagai kesalahan akan menyebabkan build gagal sehingga Anda tidak dapat mengabaikan kesalahan tersebut. Untuk memperlakukan peringatan sebagai kesalahan, sampaikan -Werrorke kompiler.

SS Anne
sumber
4

Peringatan kompiler di C ++ sangat berguna untuk beberapa alasan.

1 - Ini memungkinkan untuk menunjukkan kepada Anda di mana Anda dapat melakukan kesalahan yang dapat berdampak pada hasil akhir operasi Anda. Sebagai contoh jika Anda tidak menginisialisasi variabel atau jika Anda meletakkan "=" bukannya "==" (hanya ada contoh)

2 - Ini juga memungkinkan untuk menunjukkan kepada Anda di mana kode Anda tidak sesuai dengan standar c ++. Ini berguna karena jika kode sesuai dengan standar aktual, akan mudah untuk memindahkan kode ke bentuk plat lain misalnya.

Secara umum, peringatan sangat berguna untuk menunjukkan kepada Anda di mana Anda memiliki kesalahan dalam kode Anda yang dapat mempengaruhi hasil algoritma Anda atau mencegah beberapa kesalahan saat pengguna akan menggunakan program Anda.

Fizik26
sumber
4

Mengabaikan peringatan berarti Anda meninggalkan kode ceroboh yang tidak hanya dapat menyebabkan masalah di masa depan untuk orang lain, tetapi juga akan membuat pesan kompilasi penting kurang diperhatikan oleh Anda. Semakin banyak output kompiler, semakin sedikit orang akan memperhatikan atau mengganggu. Lebih bersih lebih baik. Itu juga berarti Anda tahu apa yang Anda lakukan. Peringatan sangat tidak profesional, ceroboh, dan berisiko.

Kirk Augustin
sumber
4

Saya pernah bekerja di perusahaan besar (Fortune 50) yang memproduksi peralatan pengujian elektronik.

Produk inti dari grup saya adalah program MFC yang, selama bertahun-tahun, menghasilkan ratusan peringatan. Yang diabaikan dalam hampir semua kasus.

Ini adalah mimpi buruk ketika bug terjadi.

Setelah posisi itu, saya cukup beruntung untuk dipekerjakan sebagai pengembang pertama dalam startup baru.

Saya mendorong kebijakan 'tidak ada peringatan' untuk semua bangunan, dengan tingkat peringatan penyusun diatur menjadi sangat berisik.

Praktik kami adalah menggunakan peringatan #pragma - push / disable / pop untuk kode yang yakin pengembang benar-benar baik, bersama dengan pernyataan log di tingkat debug, untuk berjaga-jaga.

Latihan ini berhasil bagi kami.

Jim In Texas
sumber
1
Diperbantukan. #pragma warningtidak hanya menekan peringatan, itu melayani tujuan ganda dengan cepat berkomunikasi dengan programmer lain bahwa ada sesuatu yang disengaja dan tidak disengaja, dan bertindak sebagai tag pencarian untuk dengan cepat menemukan area yang berpotensi bermasalah ketika sesuatu rusak tetapi memperbaiki kesalahan / peringatan tidak memperbaikinya.
Justin Time - Pasang kembali Monica
Anda benar Justin, itulah tepatnya yang saya lihat #pragma warning
Jim In Texas
3

Peringatan adalah kesalahan yang menunggu untuk terjadi. Jadi, Anda harus mengaktifkan peringatan kompiler dan merapikan kode Anda untuk menghapus peringatan apa pun.

josyb
sumber
3

Hanya ada satu masalah dengan memperlakukan peringatan sebagai kesalahan: Ketika Anda menggunakan kode yang berasal dari sumber lain (misalnya, perpustakaan mikro $ ** t, proyek sumber terbuka), mereka tidak melakukan tugasnya dengan benar, dan menyusun kode mereka menghasilkan banyak peringatan.

Saya selalu menulis kode saya sehingga tidak menghasilkan peringatan atau kesalahan, dan membersihkannya sampai kompilasi tanpa menghasilkan suara asing. Sampah yang harus saya kerjakan membuat saya terkejut, dan saya terkejut ketika saya harus membangun sebuah proyek besar dan menyaksikan arus peringatan yang berlalu di mana kompilasi seharusnya hanya mengumumkan file mana yang diprosesnya.

Saya juga mendokumentasikan kode saya karena saya tahu biaya perangkat lunak yang sebenarnya seumur hidup sebagian besar berasal dari pemeliharaan, bukan dari penulisan awalnya, tapi itu cerita yang berbeda ...

FKEinternet
sumber
Jangan ketuk itu, ada uang yang baik dalam pekerjaan konsultasi untuk orang-orang yang dapat membaca peringatan kompiler dengan keras kepada klien.
Móż
Kode dari sumber lain yang menghasilkan peringatan tidak perlu berarti bahwa penulis ceroboh. Ini juga bisa berarti bahwa mereka mengkompilasi kode dengan kompiler berbeda yang menghasilkan serangkaian peringatan yang berbeda. Kode dapat dikompilasi tanpa peringatan di satu kompiler, dan menghasilkan peringatan di yang lain. Atau mungkin itu hanya serangkaian opsi peringatan yang berbeda; misalnya mereka digunakan -Walldan Anda gunakan -Wall -Wextra.
celtschk
2

Beberapa peringatan bisa berarti kemungkinan kesalahan semantik dalam kode atau kemungkinan UB. Misalnya ;setelah if(), variabel yang tidak digunakan, variabel global yang ditutup oleh lokal, atau perbandingan yang ditandatangani dan yang tidak ditandatangani. Banyak peringatan terkait dengan penganalisa kode statis dalam kompiler atau untuk pelanggaran standar ISO yang terdeteksi pada waktu kompilasi, yang "memerlukan diagnostik". Sementara kejadian-kejadian itu mungkin legal dalam satu kasus tertentu, mereka akan menjadi hasil dari masalah desain sebagian besar waktu.

Beberapa kompiler, misalnya gcc, memiliki opsi baris perintah untuk mengaktifkan mode "peringatan sebagai kesalahan", itu adalah alat yang bagus, jika kejam, untuk mendidik pembuat kode pemula.

Swift - Friday Pie
sumber
1

Fakta bahwa kompiler C ++ menerima kode kompilasi yang jelas menghasilkan perilaku yang tidak terdefinisi sama sekali adalah kelemahan utama dalam kompiler. Alasan mereka tidak memperbaiki ini adalah karena hal itu mungkin akan merusak beberapa build yang dapat digunakan.

Sebagian besar peringatan harus merupakan kesalahan fatal yang mencegah pembangunan selesai. Default untuk hanya menampilkan kesalahan dan tetap melakukan kesalahan adalah salah dan jika Anda tidak menimpanya untuk memperlakukan peringatan sebagai kesalahan dan meninggalkan beberapa peringatan maka kemungkinan Anda akan berakhir dengan crash dan melakukan hal-hal acak.

Jason Livesay
sumber
Ironisnya, banyak perilaku tidak terdefinisi sebenarnya tidak menyebabkan peringatan, tetapi diam-diam mengkompilasi menjadi bom waktu kecil yang jahat. ; P
Justin Time - Reinstate Monica
1
Masalahnya adalah bahwa jika standar menuntut pesan kesalahan, pesan kesalahan itu harus dikeluarkan dalam semua kasus di mana masalah terjadi, tetapi tidak pernah jika masalah tidak terjadi. Tetapi dalam kasus-kasus seperti perilaku yang tidak terdefinisi, itu mungkin tidak mungkin untuk diputuskan. Misalnya, pertimbangkan kode berikut:int i; if (fun1()) i=2; if (fun2()) i=3; char s="abcde"[i]; ini menunjukkan perilaku yang tidak terdefinisi jika dan hanya jika keduanya fun1()dan fun2()dapat kembali falsepada eksekusi fungsi yang sama. Yang mana mungkin atau mungkin tidak benar, tetapi bagaimana cara memberitahu kompiler?
celtschk
-2

Anda pasti harus mengaktifkan peringatan kompiler karena beberapa kompiler buruk dalam melaporkan beberapa kesalahan pemrograman umum, termasuk yang berikut: -

-> menginisialisasi variabel yang dilupakan -> mengembalikan nilai dari fungsi yang terlewatkan -> argumen sederhana dalam keluarga printf dan scanf tidak cocok dengan format string fungsi digunakan tanpa dideklarasikan sebelumnya, meskipun terjadi pada c saja

Jadi karena fungsi-fungsi ini dapat dideteksi dan dilaporkan, biasanya tidak secara default; jadi fitur ini harus diminta secara eksplisit melalui opsi kompiler.

Hasan Raza
sumber
-32

Tenang saja: Anda tidak harus, itu tidak perlu. -Wall and -Werror dirancang oleh maniak kode-refactoring untuk diri mereka sendiri: itu diciptakan oleh pengembang kompiler untuk menghindari build yang ada setelah pembaruan kompiler di sisi pengguna . Fiturnya tidak ada apa-apanya, tetapi semua tentang keputusan untuk istirahat atau tidak untuk merusak build.

Ini sepenuhnya tergantung pada preferensi Anda untuk menggunakannya atau tidak. Saya menggunakannya sepanjang waktu karena membantu saya memperbaiki kesalahan saya.

sqr163
sumber
19
Meskipun tidak wajib , sangat disarankan untuk menggunakannya
Spikatrix
18
-Wall and -Werror was designed by code-refactoring maniacs for themselves.[rujukan?]
YSC
22
Sepertinya Anda menentang diri sendiri. Jika Anda "menggunakannya sepanjang waktu karena membantu memperbaiki kesalahan [Anda]," bukankah itu layak untuk diajarkan kepada programmer yang lebih baru sehingga mereka akan melakukannya di mana saja sejak awal? Saya tidak berpikir pertanyaan ini menanyakan apakah mungkin untuk dikompilasi tanpa -Wallatau tidak -Werror, dan hanya menanyakan apakah itu ide yang bagus. Yang mana, dari kalimat terakhir Anda, sepertinya Anda mengatakannya.
scohe001
12
Ketika Anda mendapatkan lebih banyak pengalaman dengan mempertahankan kode yang tidak ditulis oleh Anda, kunjungi kembali jawaban ini.
Thorbjørn Ravn Andersen
Ini bukan jawaban yang bermanfaat. Ada 4 tanda tanya dalam pertanyaan OP. Berapa banyak jawaban jawaban ini?
Anders