Bagaimana cara efektif melakukan debugging manual? [Tutup]


8

Katakanlah Anda tidak memiliki debugger yang tersedia, apa yang akan menjadi pendekatan yang efektif untuk kode debug yang tidak berfungsi (seperti yang diharapkan)?


20
"Alat debugging yang paling efektif masih dipikirkan dengan cermat, ditambah dengan pernyataan cetak yang ditempatkan dengan bijaksana." - Brian Kernighan

3
Setuju. Sebagian besar alat debugging yang kuat masih mencetak pernyataan. Saran lain adalah men-debug kode aktual dan bukan komentar.
romeroqj

4
@ jromero: saya tidak akan mengatakan pernyataan cetak adalah "yang paling kuat". Paling luas dan mudah digunakan, tentu saja.
whatsisname

1
Kutipan Kernighan itu membuatku berharap aku bisa menurunkan komentar. Debugging pernyataan cetak adalah alat pilihan terakhir.
Mason Wheeler

2
@Mason: Pertanyaannya mengasumsikan debuggers tidak tersedia (jadi cara "nyata" untuk melacak eksekusi hilang), jadi apa lagi yang akan Anda gunakan untuk melacak eksekusi?

Jawaban:


7

Ada sejumlah teknik:

  1. Penebangan. Jika Anda tidak punya akses file, masuk ke konsol serial, atau perangkat output apa pun yang tersedia. Adalah ide yang baik untuk selalu menulis kode Anda dengan log in, memungkinkan kompilasi bersyarat untuk level logging yang berbeda, dari 'tidak ada' menjadi 'overbloated'.

  2. Memotongnya. Kecualikan bagian-bagian kode Anda di sekitar titik bug yang dicurigai satu per satu, dan analisis apa yang telah Anda lakukan ketika bug menghilang.

  3. Pernyataan atau kontrak. Merupakan ide bagus untuk mengisikan kode Anda dengan menegaskan dari awal. Mereka tidak hanya membantu dengan debugging, tetapi juga berfungsi sebagai dokumentasi tambahan untuk kode Anda.

  4. Mirip dengan 2. - ubah input Anda dan ganti kode kecuali bug tersebut hilang atau ubah perilakunya. Ini sering merupakan ide yang baik untuk bermain dengan berbagai level optimisasi (jika Anda mengkode dalam C atau C ++), karena bug yang berhubungan dengan pointer cenderung sangat fluktuatif dalam perilaku mereka.

  5. Versi otomatis 3. - gunakan kode yang diinstrumentasi, misalnya, jalankan biner di bawah valgrind.

Dan tentu saja ada lebih banyak alat dan trik, tergantung pada sifat lingkungan eksekusi Anda dan kode Anda.


1
-1: Tidak bisa setuju 4). Anda tampaknya mengusulkannya sebagai solusi untuk bug? Jika demikian itu jahat dan Anda memiliki masalah. Yang dilakukannya hanyalah membuat gejalanya hilang - itu masih ada, Anda baru saja menyembunyikannya .... untuk sekarang ....
mattnz

@ mattnz, pikiran menjelaskan? Saya mengusulkan pendekatan ini sebagai alternatif untuk debugger interaktif. Yang, pada gilirannya, hanya menyoroti gejala, bukan penyebab sebenarnya. 4) adalah cara untuk mengidentifikasi masalah, bukan solusi. Sebenarnya, pendekatan saya jauh lebih baik daripada debugging dalam banyak kasus, karena memberikan cakupan yang lebih baik. Jadi, kemungkinan Anda tidak mengerti apa yang saya usulkan. Coba baca lagi.
SK-logic

Saya telah melihat pengembang menggunakan tindakan yang ditunjukkan pada Langkah 4 untuk "memperbaiki" cacat menggunakan "Saya bisa mewujudkannya, sekarang saya tidak bisa, saya sudah memperbaikinya - kirimkan". Pos Anda menyarankan metode ini memberikan perbaikan bug yang valid.
mattnz

@ mattnz, tidak, itu tidak menyarankan hal seperti ini. Saya menjelaskan cara untuk menyelidiki bug, bukan untuk memperbaikinya. Debuggers tidak memperbaiki bug, dan pertanyaannya adalah tentang alternatif untuk debugger.
SK-logic

18

Dapatkan seorang kolega dan jelaskan masalahnya secara detail saat Anda berjalan melewati kode yang merepotkan langkah demi langkah.

Sering kali tindakan menjelaskan menjelaskannya kepada kolega Anda atau diri Anda sendiri.


12
+1 Dan jika Anda tidak menemukan kolega, gunakan boneka beruang teddy .
Péter Török

4
@ Péter Török: Saya tidak tahu ... boneka beruang cenderung untuk menatap balik dengan mata kancingnya yang dingin ... mengabaikan semua yang Anda katakan, membuat Anda merasa tidak berharga, kecil, tidak berarti ... Itu membuat debugging dengan boneka beruang .. sulit.
FrustratedWithFormsDesigner

1
@FrustratedWithFormsDesigner, silakan lihat tautan yang saya tambahkan.
Péter Török

2
@ Peter, saya khawatir memiliki rak yang penuh teddybears yang siap untuk diambil oleh rekan kerja untuk didebug, mungkin membuat kesan yang salah pada pelanggan.

1
@FrustratedWithFormsDesigner: Dan apa bedanya dengan banyak rekan
mattnz

3

Apakah ada sistem logging untuk mengelola hasil program? Apakah setidaknya ada konsol untuk dicetak atau file yang dapat Anda tulis? Menggunakan konsol atau file log adalah cara Anda dapat melakukan debug tanpa debugger. Berikan input pada program agar Anda tahu apa yang seharusnya menjadi output, kemudian verifikasi bahwa output bekerja dan pastikan logging Anda memberi Anda banyak detail dari proses. Kemudian coba dengan input yang memberikan output yang salah. mudah-mudahan, log akan memberi Anda jejak terperinci dari apa yang salah.


Anda dapat menggunakan apa saja TETAPI debugger dari jenis gdb atau apa yang akan Anda temukan di IDE
Anto

@Anto: Kedengarannya seperti baris dari tugas pekerjaan rumah, tetapi dalam kasus itu masuk ke file atau konsol tidak menggunakan debugger seperti "gdb atau apa yang Anda temukan di IDE Anda". gdb dan debugger lain memungkinkan Anda untuk melangkah melalui kode baris per baris dan memeriksa nilai-nilai variabel saat program berjalan . Debugging-by-log berarti Anda harus menggunakan jejak (dalam file atau konsol) dari eksekusi program setelah selesai, dan mencari tahu apa yang terjadi.
FrustratedWithFormsDesigner

Saya tahu, oleh karena itu, apa yang Anda rekomendasikan diizinkan. Tidak, ini bukan tugas pekerjaan rumah; Saya di sekolah menengah dan kami tidak memiliki pemrograman / cs sama sekali.
Anto

2
@Anto: Oke. Satu-satunya downside ke metode ini adalah jika Anda mencoba untuk debug program yang memiliki masalah sinkronisasi. Misalnya, jika ini adalah masalah IPC maka laporan cetak / log Anda mungkin memengaruhi seberapa cepat proses berbicara satu sama lain dan mengaktifkan atau menonaktifkan pencatatan dapat memengaruhi apakah masalah tersebut direproduksi (dalam hal ini, Anda benar-benar harus menggunakan @ Saran Thorbjørn Ravn Andersen). Dalam beberapa kasus, logging dapat sangat menurunkan kinerja, tetapi biasanya hanya ketika banyak logging di sistem besar ketika memproses data yang sangat besar ... tetapi sesuatu yang harus diperhatikan.
FrustratedWithFormsDesigner

3

Tergantung. Apakah itu berhasil sebelumnya? Jika kode yang digunakan untuk bekerja tiba-tiba rusak, maka Anda harus sangat hati-hati memeriksa perubahan terbaru.


2
Pendekatan ini tidak boleh diremehkan: riwayat revisi adalah cara yang bagus untuk mengidentifikasi kesalahan dalam kode yang sebelumnya bekerja - bahkan ketika menambahkan fitur baru.
edA-qa mort-ora-y

2
Saya pernah mendengar bahwa 'git bisect' mengotomatiskan tugas ini. Saya belum mencobanya.
Clayton Stanley

2

1) Lakukan apa yang perlu Anda lakukan untuk membuat bug 100% dapat diproduksi kembali, atau hampir 100% yang Anda bisa

2) Lacak kembali masalahnya, menggunakan printf () atau fasilitas logging lainnya. Ini adalah seni, dan itu tergantung pada sifat bug.

Jika Anda sama sekali tidak tahu tentang lokasi bug, tetapi misalnya Anda tahu suatu kondisi menjadi salah di beberapa titik (keadaan program rusak - sebut saja isBroken ()), Anda dapat melakukan pencarian menelusuri / partisi untuk mencari tahu lokasi masalahnya. Misalnya, catat nilai isBroken () di awal di akhir metode utama:

void doSomething (void)
{
    printf("START doSomething() : %d\n", isBroken());
    doFoo();
    doBar();
    printf("END doSomething() : %d\n", isBroken());
}

Jika dalam log Anda lihat

START doSomething() : 0
END doSomething() : 1

Anda tahu ada yang salah di sana. Jadi, Anda menghapus semua kode logging lainnya, dan coba versi baru ini:

void doSomething (void)
{
    printf("START doSomething() : %d\n", isBroken());
    doFoo();
            printf("AFTER doFoo() : %d\n", isBroken());
    doBar();
    printf("END doSomething() : %d\n", isBroken());
}

Sekarang dalam log Anda mungkin melihat ini

START doSomething() : 0
AFTER doFoo() : 0
END doSomething() : 1

Jadi sekarang Anda tahu doBar () memicu bug, dan Anda dapat mengulangi prosedur di atas di doBar (). Idealnya, Anda akan mempersempit kesalahan menjadi satu baris.

Tentu saja ini dapat membantu Anda mengungkapkan gejala bug dan bukan penyebab root - misalnya, Anda menemukan pointer NULL yang tidak boleh NULL, tetapi mengapa? Anda kemudian dapat login lagi, tetapi memeriksa kondisi "rusak" yang berbeda.

Jika Anda mengalami kerusakan alih-alih keadaan yang rusak, ini kurang lebih sama - baris terakhir dari log memberi Anda petunjuk tentang di mana hal-hal rusak.


2

Setelah jawaban lain gagal , selalu ada debugging pencarian biner :

  1. Hilangkan sebagian tertentu (lebih disukai setengah) dari kemungkinan penyebab (baris kode, revisi , masukan, dll)
  2. Cobalah untuk mereproduksi masalah lagi.
  3. Jika masalah berlanjut: kembali ke langkah 1.
  4. Jika Anda hanya memiliki satu penyebab (baris kode, revisi, bagian input, dll.) Yang tersisa: hore! Prosedur keluar.
  5. Jika tidak: kembalikan langkah 1, dan sekarang hilangkan setengah lainnya .
  6. Kembali ke langkah 2.

Catatan: jelas, teknik ini hanya berfungsi jika Anda dapat mereproduksi masalah dengan andal.


1. Hilangkan setengah dari kemungkinan penyebabnya. Masalah hilang. 2. Kembalikan setengah itu, dan hilangkan yang lain. Masalah hilang. 3. Hilangkan hanya beberapa kemungkinan penyebab. Masalah hilang jika Anda menghilangkan 20% dari mereka. 4. Mulai memeriksa kinerja, mesin yang mendasarinya dan berjalan dalam lingkaran. 5. Panik.
SF.

Dengan surat-surat besar dan ramah.
Jeroen

0

'"Alat debugging paling efektif masih dipikirkan dengan cermat, ditambah dengan pernyataan cetak yang ditempatkan dengan bijaksana." - Brian Kernighan 'Pada hari itu mungkin benar! Metode yang paling efektif adalah dengan melihat unit test tetapi tebakan saya adalah Anda tidak memilikinya.


Saya tidak memiliki tes unit karena saya tidak memiliki proyek atau kode tertentu; Aku hanya meminta metode debugging
Anto

Kenapa Anda memilih jawaban ini? Berhenti kencing di kegelapan dan tes unit kemudian.

Bukan aku yang turun jadi menangislah ke orang lain
Anto

2
Pengujian unit tidak menggantikan debugging, itu hanya membantu kompartementalisasi dan membatasi bug. Yang membuat debugging lebih sederhana, ketika bug muncul muncul dalam uji unit kode. IME, sebagian besar bug rumit dalam interaksi komponen (sulit untuk unit test), dan terlihat lebih sering di suite tes basher gaya regresi.
Clayton Stanley

-1) Bagaimana Anda memperbaiki kode yang diidentifikasi oleh unit test yang rusak - Anda debug itu ...... Tes unit mendeteksi bug, debugger dan debugging digunakan untuk memperbaiki cacat.
mattnz

0

Itu tergantung bug.

Jika bug adalah jenis 'mengapa kode melakukan A', maka dapat bermanfaat untuk menguji pemahaman Anda sendiri tentang kode di sekitar lokasi 'kode melakukan A'. Perkenalkan kode baru yang Anda harapkan menghasilkan bug baru (kode ini harus membuatnya menjadi B, ini harus membuatnya menjadi C). Saya biasanya dengan cepat menemukan beberapa kode baru yang menghasilkan perilaku yang tidak saya harapkan. Lalu saya menunggu dengan sabar sementara pikiran saya membangun model mental yang diperbarui dari perilaku kode sehingga perubahan terakhir masuk akal, dan kemudian perubahan model mental itu biasanya menjelaskan mengapa kode itu melakukan A.

Kasus kedua telah dibahas secara rinci di sini. Di mana Anda telah mewarisi kode, tidak memiliki model mental yang solid tentang cara kode bekerja, tidak memiliki ide yang baik tentang lokasi spesifik bug, dll. Dalam hal ini, menelusuri / membagi-dan- metode menaklukkan dengan pernyataan cetak dapat bekerja. Dan jika itu di bawah kendali sumber, pastikan untuk memeriksa perubahan kode terbaru.


0

Memperluas pada "Alat debugging paling efektif masih dipikirkan dengan cermat, ditambah dengan pernyataan cetak yang ditempatkan dengan bijaksana."

Pertama, coba persempit saat bug terjadi. Jadikan gejala yang dapat diamati pengguna dapat diamati sistem. (katakanlah, beberapa string berubah menjadi omong kosong, tambahkan loop yang polling konten skrip dan memicu debug Anda saat itu berubah.) Tentu saja jika kesalahannya adalah crash, tambahkan penanganan segfault.

Kemudian coba persempit utasnya jika masalahnya pada lingkungan multi-utas. Berikan masing-masing utas pengidentifikasi, dan buang saat bug terjadi.

Setelah Anda memiliki utas, taburkan kode utas yang diberikan dengan printfs secara berlebihan untuk memakukan titik di mana ia muncul.

Kemudian telusur balik ke tempat tindakan aktual yang membuatnya terjadi (tindakan destruktif akan sering sedikit sebelum di mana data yang rusak memicu masalah.) Periksa apa struktur / variabel yang terjadi di dekatnya dalam memori, amati loop yang mempengaruhi mereka, periksa poin di mana nilai rusak ditulis untuk.

Setelah Anda memiliki poin yang menyebabkan masalah, sebelum memperbaikinya, pikirkan dua kali perilaku yang benar.

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.