Bug seperti apa yang ditimbulkan oleh pernyataan “kebagian”? Apakah ada contoh signifikan secara historis?

103

Saya mengerti bahwa simpan untuk keluar dari loop bersarang di loop; yang gotopernyataan menghindari dan dicerca sebagai bug gaya rawan pemrograman, untuk tidak pernah digunakan.

XKCD Alt Text: "Neal Stephenson berpikir itu lucu untuk menamai labelnya 'dengo'"
Lihat komik aslinya di: http://xkcd.com/292/

Karena saya belajar ini sejak dini; Saya tidak benar-benar memiliki wawasan atau pengalaman tentang jenis bug apa yang gotosebenarnya mengarah. Jadi apa yang kita bicarakan di sini:

  • Ketidakstabilan?
  • Kode tidak dapat dipertahankan atau tidak dapat dibaca?
  • Kerentanan keamanan?
  • Sesuatu yang lain sama sekali?

Bug seperti apa yang ditimbulkan oleh pernyataan "kebagian"? Apakah ada contoh signifikan secara historis?

Akiva
sumber
33
Sudahkah Anda membaca makalah pendek asli Dijkstra tentang topik ini? (Itu adalah pertanyaan Ya / Tidak, dan jawaban apa pun selain instan yang tegas "ya" adalah "tidak".)
John R. Strohm
2
Saya kira alarm keluar adalah ketika sesuatu kegagalan bencana terjadi. di mana Anda tidak akan pernah kembali. Seperti listrik mati, perangkat atau file hilang. Beberapa jenis "pada kesalahan goto" ... Tapi saya pikir sebagian besar kesalahan "hampir bencana" dapat ditangani oleh konstruksi "coba - tangkap" saat ini.
Lenne
13
Belum ada yang menyebutkan perhitungan GOTO. Kembali ketika bumi masih muda, BASIC memiliki nomor baris. Anda dapat menulis yang berikut ini: 100 N = A * 100; GOTO N. Coba debug itu :)
mcottle
7
@ JohnR.Strohm Saya telah membaca makalah Dijkstra. Itu ditulis pada tahun 1968 dan menunjukkan bahwa kebutuhan untuk goto dapat dikurangi dalam bahasa yang mencakup fitur-fitur canggih seperti pernyataan dan fungsi switch. Itu ditulis sebagai respons terhadap bahasa di mana goto adalah metode utama kontrol aliran, dan dapat digunakan untuk melompat ke titik mana pun dalam program. Sedangkan dalam bahasa yang dikembangkan setelah makalah ini ditulis, misalnya C, goto hanya bisa melompat ke tempat-tempat dalam bingkai tumpukan yang sama, dan umumnya digunakan hanya ketika opsi lain tidak berfungsi dengan baik. (lanjutan ...)
Ray
10
(... lanjutan) Poinnya valid pada saat itu, tetapi tidak lagi relevan, terlepas dari apakah kebotakan adalah ide yang bagus atau tidak. Jika kita ingin memperdebatkan itu dengan satu atau lain cara, harus ada argumen yang berhubungan dengan bahasa modern. Ngomong-ngomong, sudahkah Anda membaca "Pemrograman Terstruktur dengan Pernyataan Goto" dari Knuth?
Ray

Jawaban:

2

Ini cara untuk melihatnya. Saya belum melihat jawaban yang lain.

Ini tentang ruang lingkup. Salah satu pilar utama praktik pemrograman yang baik adalah menjaga ruang lingkup Anda tetap ketat. Anda membutuhkan ruang lingkup yang ketat karena Anda tidak memiliki kemampuan mental untuk mengawasi dan memahami lebih dari sekadar beberapa langkah logis. Jadi, Anda membuat blok kecil (masing-masing menjadi "satu hal") dan kemudian membangun dengan itu untuk membuat blok yang lebih besar yang menjadi satu hal, dan seterusnya. Ini menjaga hal-hal dapat dikelola dan dipahami.

Goto secara efektif mengembang cakupan logika Anda ke seluruh program. Ini pasti akan mengalahkan otak Anda untuk apa pun kecuali program terkecil yang hanya mencakup beberapa baris.

Jadi, Anda tidak akan dapat mengetahui apakah Anda melakukan kesalahan lagi karena terlalu banyak untuk menerima dan memeriksa kepala kecil Anda yang malang. Ini adalah masalah sebenarnya, bug hanyalah hasil yang mungkin.

Martin Maat
sumber
Goto non-lokal?
Deduplicator
thebrain.mcgill.ca/flash/capsules/experience_jaune03.html << Pikiran manusia dapat melacak rata-rata 7 hal sekaligus. Dasar pemikiran Anda berperan dalam batasan ini, karena ruang lingkup yang diperluas akan menambah lebih banyak hal yang perlu diperhatikan. Dengan demikian jenis bug yang akan diperkenalkan cenderung salah satu dari kelalaian dan kelupaan. Anda juga menawarkan strategi yang meringankan dan praktik yang baik secara umum, "menjaga cakupan Anda tetap ketat". Karena itu, saya menerima jawaban ini. Martin, pekerjaan yang bagus.
Akiva
1
Betapa kerennya itu?! Di antara lebih dari 200 suara diberikan, menang hanya dengan 1!
Martin Maat
68

Bukannya itu gotoburuk dengan sendirinya. (Lagi pula, setiap instruksi lompatan di komputer adalah kebohongan.) Masalahnya adalah bahwa ada gaya manusia pemrograman yang pra-tanggal pemrograman terstruktur, apa yang bisa disebut pemrograman "diagram alur".

Dalam pemrograman diagram alir (yang dipelajari oleh generasi saya, dan digunakan untuk program Apollo moon) Anda membuat diagram dengan blok untuk eksekusi pernyataan dan berlian untuk keputusan, dan Anda bisa menghubungkannya dengan garis yang mengarah ke mana-mana. (Disebut "kode spageti".)

Masalah dengan kode spaghetti adalah bahwa Anda, sang programmer, bisa "tahu" itu benar, tetapi bagaimana Anda bisa membuktikannya , kepada diri sendiri atau orang lain? Bahkan, itu mungkin sebenarnya memiliki potensi kelakuan buruk, dan pengetahuan Anda bahwa itu selalu benar bisa salah.

Seiring datang pemrograman terstruktur dengan blok awal-akhir, untuk, sementara, jika-lain, dan sebagainya. Ini memiliki keuntungan bahwa Anda masih bisa melakukan apa pun di dalamnya, tetapi jika Anda sama sekali berhati-hati, Anda bisa yakin kode Anda benar.

Tentu saja, orang masih dapat menulis kode spageti bahkan tanpa itu goto. Metode umum adalah menulis a while(...) switch( iState ){..., di mana kasus yang berbeda mengatur nilai yang iStateberbeda. Bahkan, dalam C atau C ++ orang dapat menulis makro untuk melakukan itu, dan beri nama GOTO, jadi mengatakan Anda tidak menggunakan gotoadalah perbedaan tanpa perbedaan.

Sebagai contoh bagaimana pembuktian kode dapat menghalangi tanpa batasan goto, sejak lama saya menemukan struktur kontrol yang berguna untuk antarmuka pengguna yang berubah secara dinamis. Saya menyebutnya eksekusi diferensial . Hal ini sepenuhnya Turing-universal, tetapi bukti kebenarannya tergantung pada pemrograman terstruktur murni - tidak ada goto, return, continue, break, atau pengecualian.

masukkan deskripsi gambar di sini

Mike Dunlavey
sumber
49
Kebenaran tidak dapat dibuktikan kecuali dalam program yang paling sepele, bahkan ketika pemrograman terstruktur digunakan untuk menulisnya. Anda hanya dapat meningkatkan tingkat kepercayaan diri Anda; pemrograman terstruktur mencapai itu.
Robert Harvey
23
@MikeDunlavey: Terkait: "Waspadalah terhadap bug dalam kode di atas; Saya hanya membuktikannya benar, tidak mencobanya." staff.fnwi.uva.nl/p.vanemdeboas/knuthnote.pdf
Mooing Duck
26
@RobertHarvey Tidak sepenuhnya benar bahwa bukti kebenaran hanya praktis untuk program sepele. Namun, alat yang lebih khusus daripada pemrograman terstruktur diperlukan.
Mike Haskel
18
@ MSalters: Ini adalah proyek penelitian. Tujuan dari proyek penelitian tersebut adalah untuk menunjukkan bahwa mereka dapat menulis kompiler terverifikasi jika mereka memiliki sumber daya. Jika Anda melihat karya mereka saat ini, Anda akan melihat bahwa mereka sama sekali tidak tertarik mendukung versi C yang lebih baru, tetapi mereka tertarik untuk memperluas sifat kebenaran yang dapat mereka buktikan. Dan untuk itu, sama sekali tidak relevan apakah mereka mendukung C90, C99, C11, Pascal, Fortran, Algol, atau Plankalkül.
Jörg W Mittag
8
@martineau: Saya curiga dengan "frase boson", di mana programmer agak setuju bahwa itu buruk atau baik, karena mereka akan duduk jika tidak. Harus ada alasan yang lebih mendasar untuk berbagai hal.
Mike Dunlavey
63

Mengapa kebotakan berbahaya?

  • gototidak menyebabkan ketidakstabilan dengan sendirinya. Meskipun sekitar 100.000 gotodetik, kernel Linux masih menjadi model stabilitas.
  • gotodengan sendirinya seharusnya tidak menyebabkan kerentanan keamanan. Namun dalam beberapa bahasa, mencampurnya dengan try/ catchblok manajemen pengecualian dapat menyebabkan kerentanan seperti yang dijelaskan dalam rekomendasi CERT ini . Kompilator Mainstream menandai flag dan mencegah kesalahan seperti itu, tetapi sayangnya, kompiler yang lebih lama atau lebih eksotis tidak.
  • gotomenyebabkan kode tidak terbaca dan tidak dapat dipelihara. Ini juga disebut kode spageti , karena, seperti pada piring spageti, sangat sulit untuk mengikuti aliran kontrol ketika ada terlalu banyak foto.

Bahkan jika Anda berhasil menghindari kode spageti dan jika Anda hanya menggunakan beberapa foto, mereka masih memfasilitasi bug seperti dan sumber daya bocor:

  • Kode yang menggunakan pemrograman struktur, dengan blok dan loop bersarang yang jelas, mudah diikuti; alur kontrolnya sangat mudah ditebak. Karena itu lebih mudah untuk memastikan bahwa invarian dihormati.
  • Dengan sebuah gotopernyataan, Anda mematahkan aliran langsung itu, dan mematahkan harapan. Misalnya, Anda mungkin tidak menyadari bahwa Anda masih harus membebaskan sumber daya.
  • Banyak gototempat yang berbeda dapat mengirim Anda ke satu target goto. Jadi tidak jelas untuk mengetahui dengan pasti keadaan Anda saat mencapai tempat ini. Risiko membuat asumsi yang salah / tidak berdasar karenanya cukup besar.

Informasi dan kutipan tambahan:

C memberikan gotopernyataan dan label yang tak dapat disalahgunakan yang tak terbatas untuk dicabuti . Secara formal gototidak pernah diperlukan, dan dalam praktiknya hampir selalu mudah untuk menulis kode tanpanya. (...)
Meskipun demikian kami akan menyarankan beberapa situasi di mana goto dapat menemukan tempat. Penggunaan yang paling umum adalah meninggalkan pemrosesan dalam beberapa struktur yang bersarang secara mendalam, seperti memecah dua loop sekaligus. (...)
Meskipun kami tidak dogmatis tentang masalah ini, tampaknya pernyataan goto harus digunakan dengan hemat, jika memang ada .

  • James Gosling & Henry McGilton menulis di kertas putih lingkungan berbahasa Jawa 1995 :

    Tidak Ada Lagi Pernyataan Goto
    Java tidak memiliki pernyataan goto. Studi menggambarkan bahwa goto (salah) digunakan lebih sering daripada tidak hanya "karena ada". Menghilangkan goto menyebabkan penyederhanaan bahasa (...) Studi pada sekitar 100.000 baris kode C menentukan bahwa sekitar 90 persen dari pernyataan goto digunakan murni untuk mendapatkan efek keluar dari loop bersarang. Seperti disebutkan di atas, multi-level istirahat dan terus menghapus sebagian besar kebutuhan untuk pernyataan goto.

  • Bjarne Stroustrup mendefinisikan goto dalam glosariumnya dalam istilah -istilah yang mengundang ini:

    goto - goto yang terkenal itu. Terutama berguna dalam mesin yang menghasilkan kode C ++.

Kapan bisa digunakan?

Seperti K&R, saya tidak dogmatis tentang goto. Saya akui bahwa ada situasi di mana kebersamaan bisa memudahkan hidup seseorang.

Biasanya, dalam C, goto memungkinkan keluar loop bertingkat, atau penanganan kesalahan yang diperlukan untuk mencapai titik keluar yang sesuai yang membebaskan / membuka semua sumber daya yang dialokasikan sejauh ini (alokasi beberapa item secara berurutan berarti beberapa label). Artikel ini mengukur berbagai penggunaan goto di kernel Linux.

Secara pribadi saya lebih suka menghindarinya dan dalam 10 tahun C, saya menggunakan maksimal 10 foto. Saya lebih suka menggunakan nested ifs, yang menurut saya lebih mudah dibaca. Ketika ini akan menyebabkan sarang terlalu dalam, saya akan memilih untuk menguraikan fungsi saya di bagian yang lebih kecil, atau menggunakan indikator boolean dalam kaskade. Kompilator pengoptimal hari ini cukup pintar untuk menghasilkan kode yang hampir sama dengan kode yang sama goto.

Penggunaan goto sangat tergantung pada bahasa:

  • Dalam C ++, penggunaan RAII yang tepat menyebabkan kompiler untuk secara otomatis menghancurkan objek yang keluar dari ruang lingkup, sehingga sumber daya / kunci tetap akan dibersihkan, dan tidak lagi membutuhkan goto.

  • Di Jawa tidak perlu untuk goto (lihat kutipan penulis Jawa di atas dan ini sangat baik jawaban Stack Overflow ): pengumpul sampah yang membersihkan kekacauan, break, continue, dan try/ catchpenanganan eksepsi mencakup semua kasus di mana gotobisa membantu, tetapi dalam lebih aman dan lebih baik cara. Popularitas Java membuktikan bahwa pernyataan goto dapat dihindari dalam bahasa modern.

Zoom pada goto SSL terkenal gagal kerentanan

Penafian Penting: mengingat diskusi yang sengit dalam komentar, saya ingin mengklarifikasi bahwa saya tidak berpura-pura bahwa pernyataan kebohongan adalah satu-satunya penyebab bug ini. Saya tidak berpura-pura bahwa tanpa goto tidak akan ada bug. Saya hanya ingin menunjukkan bahwa seorang goto dapat terlibat dalam bug serius.

Saya tidak tahu berapa banyak bug serius yang terkait gotodalam sejarah pemrograman: detail sering tidak dikomunikasikan. Namun ada bug Apple SSL terkenal yang melemahkan keamanan iOS. Pernyataan yang menyebabkan bug ini adalah gotopernyataan yang salah .

Beberapa berpendapat bahwa akar penyebab bug itu bukan pernyataan goto itu sendiri, tetapi salinan / tempel yang salah, lekukan menyesatkan, hilang kawat gigi keriting di sekitar blok bersyarat, atau mungkin kebiasaan kerja pengembang. Saya tidak dapat mengkonfirmasi salah satu dari mereka: semua argumen ini adalah hipotesis dan interpretasi yang memungkinkan. Tidak ada yang benar-benar tahu. ( Sementara itu, hipotesis gabungan yang salah seperti yang disarankan seseorang dalam komentar tampaknya menjadi kandidat yang sangat baik mengingat beberapa inkonsistensi lekukan lain dalam fungsi yang sama ).

Satu-satunya fakta obyektif adalah bahwa duplikat gotomenyebabkan keluar dari fungsi sebelum waktunya. Melihat kode tersebut, satu-satunya pernyataan tunggal yang dapat menyebabkan efek yang sama adalah pengembalian.

Kesalahan dalam fungsi SSLEncodeSignedServerKeyExchange()dalam file ini :

    if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
        goto fail;
    if ((err =...) !=0)
        goto fail;
    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
        goto fail;
        goto fail;  // <====OUCH: INDENTATION MISLEADS: THIS IS UNCONDITIONDAL!!
    if (...)
        goto fail;

    ... // Do some cryptographic operations here

fail:
    ... // Free resources to process error

Memang kurung kurawal di sekitar blok bersyarat bisa mencegah bug:
itu akan menyebabkan kesalahan sintaks saat kompilasi (dan karenanya koreksi) atau ke goto tidak berbahaya yang berlebihan. Omong-omong, GCC 6 akan dapat menemukan kesalahan ini berkat peringatan opsional untuk mendeteksi lekukan yang tidak konsisten.

Tapi pertama-tama, semua foto ini bisa dihindari dengan kode yang lebih terstruktur. Jadi goto setidaknya secara tidak langsung menjadi penyebab bug ini. Setidaknya ada dua cara berbeda yang bisa menghindarinya:

Pendekatan 1: jika klausa atau bersarang ifs

Alih-alih menguji banyak kondisi untuk kesalahan secara berurutan, dan setiap kali mengirim ke faillabel jika ada masalah, orang bisa memilih untuk mengeksekusi operasi kriptografi dalam ifpernyataan-yang hanya akan melakukannya jika tidak ada pra-kondisi yang salah:

    if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) == 0 &&
        (err = ...) == 0 ) &&
        (err = ReadyHash(&SSLHashSHA1, &hashCtx)) == 0) &&
        ...
        (err = ...) == 0 ) )
    {
         ... // Do some cryptographic operations here
    }
    ... // Free resources

Pendekatan 2: gunakan akumulator kesalahan

Pendekatan ini didasarkan pada kenyataan bahwa hampir semua pernyataan di sini memanggil beberapa fungsi untuk menetapkan errkode kesalahan, dan mengeksekusi sisa kode hanya jika err0 (yaitu, fungsi dieksekusi tanpa kesalahan). Alternatif aman dan mudah dibaca adalah:

bool ok = true;
ok =  ok && (err = ReadyHash(&SSLHashSHA1, &hashCtx))) == 0;
ok =  ok && (err = NextFunction(...)) == 0;
...
ok =  ok && (err = ...) == 0;
... // Free resources

Di sini, tidak ada goto tunggal: tidak ada risiko untuk melompat dengan cepat ke titik keluar kegagalan. Dan secara visual akan mudah menemukan garis yang tidak selaras atau terlupakan ok &&.

Konstruk ini lebih kompak. Ini didasarkan pada fakta bahwa dalam C, bagian kedua dari logika dan ( &&) dievaluasi hanya jika bagian pertama benar. Bahkan, assembler yang dihasilkan oleh kompiler pengoptimalisasi hampir setara dengan kode asli dengan gotos: Pengoptimal mendeteksi dengan sangat baik rantai kondisi dan menghasilkan kode, yang pada awalnya nilai pengembalian bukan nol melompat ke akhir ( bukti online ).

Anda bahkan bisa membayangkan pemeriksaan konsistensi di akhir fungsi yang bisa selama fase pengujian mengidentifikasi ketidakcocokan antara flag ok dan kode kesalahan.

assert( (ok==false && err!=0) || (ok==true && err==0) );

Kesalahan seperti itu secara ==0tidak sengaja diganti dengan !=0kesalahan konektor atau logis akan dengan mudah terlihat selama fase debugging.

Seperti yang dikatakan: Saya tidak berpura-pura bahwa konstruksi alternatif akan menghindari bug. Saya hanya ingin mengatakan bahwa mereka dapat membuat bug lebih sulit terjadi.

Christophe
sumber
34
Tidak, bug kegagalan Apple goto disebabkan oleh programmer yang pintar memutuskan untuk tidak menyertakan kurung kurawal setelah pernyataan if. :-) Jadi ketika programmer pemeliharaan berikutnya (atau yang sama, perbedaan yang sama) datang dan menambahkan baris kode lain yang seharusnya hanya dieksekusi ketika pernyataan if dievaluasi benar, pernyataan berjalan setiap waktu. Bam, bug "goto gagal", yang merupakan bug keamanan utama . Tapi itu pada dasarnya tidak ada hubungannya dengan fakta bahwa pernyataan goto digunakan.
Craig
47
Bug "kegagalan goto" Apple secara langsung disebabkan oleh sederet kode yang diduplikasi. Efek khusus dari bug itu disebabkan oleh garis yang menjadi bagian gotodalam ifpernyataan tanpa tanda kurung . Tetapi jika Anda menyarankan bahwa menghindar gotoakan membuat kode Anda kebal terhadap efek garis yang diduplikasi secara acak, saya punya berita buruk untuk Anda.
immibis
12
Anda menggunakan cara pintas perilaku operator boolean untuk menjalankan pernyataan melalui efek samping dan mengklaim itu lebih jelas daripada ifpernyataan? Waktu yang menyenangkan. :)
Craig
38
Jika alih-alih "gagal" ada pernyataan "gagal = benar" hal yang persis sama akan terjadi.
gnasher729
15
Bug itu disebabkan oleh pengembang yang ceroboh tidak memperhatikan apa yang dia lakukan, dan tidak membaca perubahan kode mereka sendiri. Tidak lebih, tidak kurang. Oke, mungkin melemparkan beberapa pengawasan pengujian di sana juga.
Lightness Races in Orbit
34

Artikel Dijkstra yang terkenal ditulis pada saat beberapa bahasa pemrograman benar-benar mampu membuat subrutin yang memiliki banyak titik masuk dan keluar. Dengan kata lain, Anda dapat benar-benar melompat ke tengah-tengah suatu fungsi, dan melompat keluar di sembarang tempat di dalam fungsi tersebut, tanpa benar-benar memanggil fungsi itu atau kembali darinya dengan cara konvensional. Itu masih berlaku untuk bahasa assembly. Tidak ada yang pernah berpendapat bahwa pendekatan semacam itu lebih unggul daripada metode terstruktur dalam menulis perangkat lunak yang sekarang kita gunakan.

Dalam kebanyakan bahasa pemrograman modern, fungsi sangat spesifik didefinisikan dengan satu entri dan satu titik keluar. Titik masuk adalah tempat Anda menentukan parameter ke fungsi dan memanggilnya, dan titik keluar adalah tempat Anda mengembalikan nilai yang dihasilkan dan melanjutkan eksekusi pada instruksi mengikuti panggilan fungsi asli.

Dalam fungsi itu, Anda harus dapat melakukan apa pun yang Anda inginkan, dengan alasan. Jika menempatkan satu atau dua goto dalam fungsi membuatnya lebih jelas atau meningkatkan kecepatan Anda, mengapa tidak? Inti dari suatu fungsi adalah menyita sedikit fungsionalitas yang terdefinisi dengan jelas, sehingga Anda tidak perlu memikirkan cara kerjanya secara internal lagi. Setelah ditulis, Anda cukup menggunakannya.

Dan ya, Anda dapat memiliki beberapa pernyataan pengembalian di dalam suatu fungsi; masih selalu ada satu tempat di fungsi yang tepat dari mana Anda kembali (sisi belakang fungsi, pada dasarnya). Sama sekali tidak sama dengan melompat keluar dari suatu fungsi dengan kebotakan sebelum ia memiliki kesempatan untuk kembali dengan benar.

masukkan deskripsi gambar di sini

Jadi ini bukan tentang menggunakan goto. Ini tentang menghindari pelecehan mereka. Semua orang setuju bahwa Anda dapat membuat program yang sangat berbelit-belit menggunakan gotos, tetapi Anda juga dapat melakukan hal yang sama dengan menyalahgunakan fungsi-fungsi (hanya jauh lebih mudah untuk menyalahgunakan gotos).

Untuk apa nilainya, sejak saya lulus dari program BASIC garis-nomor-gaya untuk pemrograman terstruktur menggunakan bahasa Pascal dan curly-brace, saya tidak pernah menggunakan goto. Satu-satunya waktu saya tergoda untuk menggunakan salah satunya adalah melakukan keluar awal dari loop bersarang (dalam bahasa yang tidak mendukung keluar awal multi-level dari loop), tetapi saya biasanya dapat menemukan cara lain yang lebih bersih.

Robert Harvey
sumber
2
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
maple_shaft
11

Bug seperti apa yang ditimbulkan oleh pernyataan “kebagian”? Apakah ada contoh signifikan secara historis?

Saya biasa menggunakan gotopernyataan ketika menulis program BASIC sebagai seorang anak sebagai cara sederhana untuk mendapatkan dan sementara loop (Commodore 64 BASIC tidak memiliki while-loop, dan saya terlalu tidak matang untuk belajar sintaksis yang tepat dan penggunaan for-loop ). Kode saya sering sepele, tetapi bug loop apa pun dapat langsung dikaitkan dengan penggunaan goto.

Saya sekarang menggunakan terutama Python, bahasa pemrograman tingkat tinggi yang telah menentukan itu tidak perlu untuk goto.

Ketika Edsger Dijkstra menyatakan "Goto dianggap berbahaya" pada tahun 1968 ia tidak memberikan beberapa contoh di mana bug terkait dapat disalahkan pada goto, melainkan, ia menyatakan bahwa gototidak perlu untuk bahasa tingkat yang lebih tinggi dan bahwa itu harus dihindari demi apa kami mempertimbangkan aliran kontrol normal hari ini: loop dan kondisional. Kata-katanya:

Penggunaan go to yang tidak terkendali memiliki konsekuensi langsung sehingga menjadi sangat sulit untuk menemukan serangkaian koordinat yang bermakna untuk menggambarkan proses kemajuan.
[...]
The pergi ke pernyataan seperti berdiri terlalu primitif; itu terlalu banyak undangan untuk mengacaukan program seseorang.

Dia mungkin memiliki banyak sekali contoh bug dari setiap kali dia mendebug kode gotodi dalamnya. Tetapi makalahnya adalah pernyataan posisi umum yang didukung oleh bukti yang gototidak perlu untuk bahasa tingkat yang lebih tinggi. Bug umum adalah bahwa Anda mungkin tidak memiliki kemampuan untuk menganalisis secara statis kode yang dimaksud.

Kode jauh lebih sulit untuk dianalisis secara statis dengan gotopernyataan, terutama jika Anda melompat kembali dalam aliran kontrol Anda (yang dulu saya lakukan) atau ke bagian kode yang tidak terkait. Kode dapat dan ditulis dengan cara ini. Itu dilakukan untuk sangat mengoptimalkan sumber daya komputasi yang sangat langka dan dengan demikian arsitektur mesin.

Contoh Apokrifa

Ada program blackjack yang ditemukan oleh seorang pengelola untuk dioptimalkan dengan sangat elegan tetapi juga tidak mungkin baginya untuk "memperbaiki" karena sifat kode. Itu diprogram dalam kode mesin yang sangat bergantung pada gotos - jadi saya pikir cerita ini cukup relevan. Ini adalah contoh kanonik terbaik yang dapat saya pikirkan.

Contoh Konter

Namun, sumber C dari CPython (implementasi Python yang paling umum dan referensi) menggunakan gotopernyataan untuk efek besar. Mereka digunakan untuk memotong aliran kontrol yang tidak relevan di dalam fungsi untuk sampai ke akhir fungsi, membuat fungsi lebih efisien tanpa kehilangan keterbacaan. Ini menghormati salah satu cita-cita pemrograman terstruktur - untuk memiliki satu titik keluar untuk fungsi.

Sebagai catatan, saya menemukan contoh-counter ini cukup mudah untuk dianalisis secara statis.

Aaron Hall
sumber
5
"Story of Mel" yang saya temui ada pada arsitektur aneh di mana (1) setiap instruksi bahasa mesin melakukan kebohongan setelah operasinya, dan (2) itu sangat tidak efisien untuk menempatkan urutan instruksi di lokasi memori berturut-turut. Dan program ini ditulis dalam perakitan yang dioptimalkan dengan tangan, bukan bahasa yang dikompilasi.
@MilesRout Saya pikir Anda bisa benar di sini, tetapi halaman wikipedia tentang pemrograman terstruktur mengatakan: "Penyimpangan yang paling umum, ditemukan dalam banyak bahasa, adalah penggunaan pernyataan pengembalian untuk keluar awal dari subrutin. Ini menghasilkan banyak titik keluar , bukan titik keluar tunggal yang diperlukan oleh pemrograman terstruktur. " - Anda mengatakan ini salah? Apakah Anda memiliki sumber untuk dikutip?
Aaron Hall
@ AaronHall Itu bukan arti aslinya.
Rute Mil
11

Ketika wigwam adalah seni arsitektur saat ini, pembangun mereka tidak diragukan lagi dapat memberikan saran praktis mengenai pembuatan wigwam, cara membiarkan asap keluar, dan sebagainya. Untungnya, pembangun saat ini mungkin bisa melupakan sebagian besar saran itu.

Ketika kereta kuda itu adalah seni transportasi saat ini, pengemudi mereka pasti bisa memberi Anda nasihat praktis tentang kuda-kuda kereta kuda, cara mempertahankan diri dari para perampok, dan sebagainya. Untungnya, pengendara saat ini dapat melupakan sebagian besar saran itu juga.

Ketika kartu berlubang adalah seni pemrograman saat ini, para praktisi mereka juga dapat memberi Anda saran praktis tentang pengaturan kartu, cara menghitung angka, dan sebagainya. Saya tidak yakin saran itu sangat relevan saat ini.

Apakah Anda cukup tua untuk mengetahui ungkapan "ke nomor pernyataan" ? Anda tidak perlu mengetahuinya, tetapi jika tidak, maka Anda tidak terbiasa dengan konteks historis di mana peringatan terhadapnya gotopada dasarnya relevan.

Peringatan terhadap gototidak sangat relevan hari ini. Dengan pelatihan dasar saat / untuk loop dan panggilan fungsi, Anda bahkan tidak akan berpikir untuk mengeluarkannya gotosesering mungkin. Ketika Anda memikirkannya, Anda mungkin punya alasan, jadi silakan saja.

Tapi bisakah gotopernyataan itu tidak disalahgunakan?

Jawaban: tentu saja, ini dapat disalahgunakan, tetapi penyalahgunaannya merupakan masalah yang sangat kecil dalam rekayasa perangkat lunak dibandingkan dengan jauh, kesalahan yang jauh lebih umum seperti menggunakan variabel di mana konstanta akan melayani, atau seperti pemrograman cut-and-paste (jika tidak dikenal sebagai pengabaian terhadap refactor). Saya ragu Anda dalam banyak bahaya. Kecuali jika Anda menggunakan longjmpatau mentransfer kontrol ke kode yang jauh, jika Anda berpikir untuk menggunakan gotoatau Anda hanya ingin mencobanya untuk bersenang-senang, silakan. Kamu akan baik-baik saja.

Anda mungkin memperhatikan kurangnya cerita-cerita horor terbaru yang gotomenjadi penjahat. Sebagian besar atau semua kisah ini tampaknya berusia 30 atau 40 tahun. Anda berdiri di tanah yang kokoh jika Anda menganggap cerita-cerita itu sebagian besar sudah usang.

thb
sumber
1
Saya melihat bahwa saya telah menarik setidaknya satu downvote. Yah, itu sudah diduga. Lebih banyak downvotes mungkin datang. Saya tidak akan memberikan jawaban konvensional, meskipun, ketika puluhan tahun pengalaman pemrograman telah mengajarkan kepada saya bahwa, dalam hal ini, jawaban konvensional salah. Bagaimanapun juga, ini adalah pandangan saya. Saya telah memberikan alasan saya. Pembaca dapat memutuskan.
thb
1
Posting Anda bagus, terlalu buruk, saya tidak bisa menghapus komentar.
Pieter B
7

Untuk menambahkan satu hal ke jawaban luar biasa lainnya, dengan gotopernyataan, mungkin sulit untuk mengatakan dengan tepat bagaimana Anda sampai ke tempat tertentu dalam program. Anda dapat mengetahui bahwa pengecualian terjadi pada beberapa baris tertentu tetapi jika ada gotodalam kode tidak ada cara untuk mengetahui pernyataan apa yang dieksekusi untuk menghasilkan pengecualian ini yang menyebabkan keadaan tanpa mencari keseluruhan program. Tidak ada tumpukan panggilan dan tidak ada aliran visual. Ada kemungkinan bahwa ada pernyataan 1000 baris yang menempatkan Anda dalam kondisi buruk mengeksekusi gotoke baris yang menimbulkan pengecualian.

qfwfq
sumber
1
Visual Basic 6 dan VBA memiliki penanganan kesalahan yang menyakitkan, tetapi jika Anda menggunakan On Error Goto errh, Anda bisa menggunakan Resumeuntuk mencoba lagi, Resume Nextuntuk melewati garis yang menyinggung, dan Erluntuk mengetahui baris mana itu (jika Anda menggunakan nomor baris).
Cees Timmerman
@ CeesTimmerman Saya telah melakukan sangat sedikit dengan Visual Basic, saya tidak tahu itu. Saya akan menambahkan komentar tentang itu.
qfwfq
2
@CeesTimmerman: Semantik VB6 dari "resume" mengerikan jika terjadi kesalahan dalam subrutin yang tidak memiliki blok kesalahan sendiri. Resumeakan menjalankan kembali fungsi itu dari awal, dan Resume Nextakan melewati semua fungsi yang belum.
supercat
2
@ superkat Seperti yang saya katakan, itu menyakitkan. Jika Anda perlu mengetahui baris yang tepat, Anda harus memberi nomor semuanya, atau menonaktifkan sementara penanganan kesalahan dengan On Error Goto 0dan secara manual Debug. Resumedimaksudkan untuk digunakan setelah memeriksa Err.Numberdan melakukan penyesuaian yang diperlukan.
Cees Timmerman
1
Saya harus mencatat bahwa dalam bahasa modern, gotohanya bekerja dengan garis berlabel, yang tampaknya telah digantikan oleh loop berlabel .
Cees Timmerman
7

goto lebih sulit bagi manusia untuk beralasan daripada bentuk lain dari kontrol aliran.

Memprogram kode yang benar itu sulit. Menulis program yang benar itu sulit, menentukan apakah program itu benar itu sulit, membuktikan bahwa program itu benar itu sulit.

Mendapatkan kode untuk melakukan apa yang Anda inginkan secara samar-samar itu mudah dibandingkan dengan segala sesuatu tentang pemrograman.

goto memecahkan beberapa program dengan mendapatkan kode untuk melakukan apa yang Anda inginkan. Ini tidak membantu membuat pengecekan kebenaran lebih mudah, sementara alternatifnya sering dilakukan.

Ada gaya pemrograman di mana goto adalah solusi yang tepat. Bahkan ada gaya pemrograman di mana saudara kembarnya yang jahat, datang dari, adalah solusi yang tepat. Dalam kedua kasus ini, sangat hati-hati harus dilakukan untuk memastikan Anda menggunakannya dalam pola yang dimengerti, dan banyak manual memeriksa bahwa Anda tidak melakukan sesuatu yang sulit untuk memastikan kebenaran dengan itu.

Sebagai contoh, ada fitur dari beberapa bahasa yang disebut coroutine. Coroutine adalah utas tanpa utas; negara eksekusi tanpa utas untuk menjalankannya. Anda dapat meminta mereka untuk mengeksekusi, dan mereka dapat menjalankan sebagian dari diri mereka sendiri dan kemudian menangguhkan diri mereka sendiri, menyerahkan kembali kontrol aliran.

Coroutine "Dangkal" dalam bahasa tanpa dukungan coroutine (seperti C ++ pra-C ++ 20 dan C) dimungkinkan menggunakan campuran gotos dan manajemen keadaan manual. Coroutine "Dalam" dapat dilakukan dengan menggunakan setjmpdan longjmpfungsi C.

Ada kasus di mana coroutine sangat berguna sehingga menulisnya secara manual dan hati-hati tidak sia-sia.

Dalam kasus C ++, mereka ditemukan cukup berguna sehingga mereka memperluas bahasa untuk mendukung mereka. The gotos dan manajemen negara pengguna sedang tersembunyi di balik lapisan abstraksi biaya nol, memungkinkan programmer untuk menulis mereka tanpa kesulitan karena harus membuktikan kekacauan mereka dari goto, void**s, konstruksi manual / kehancuran negara, dll benar.

Goto disembunyikan di balik abstraksi tingkat yang lebih tinggi, seperti whileatau foratau ifatau switch. Abstraksi tingkat tinggi itu lebih mudah dibuktikan dengan benar dan diperiksa.

Jika bahasa tersebut hilang beberapa dari mereka (seperti beberapa bahasa modern hilang coroutine), baik pincang bersama dengan pola yang tidak sesuai dengan masalah, atau menggunakan goto, menjadi alternatif Anda.

Membuat komputer secara samar melakukan apa yang Anda inginkan dalam kasus-kasus umum adalah mudah . Menulis kode yang andal dan tangguh itu sulit . Goto membantu yang pertama jauh lebih banyak daripada membantu yang kedua; maka "goto dianggap berbahaya", karena itu adalah tanda kode "bekerja" dangkal dengan yang dalam dan sulit untuk melacak bug. Dengan upaya yang cukup Anda masih bisa membuat kode dengan "goto" andal kuat, sehingga memegang aturan sebagai absolut itu salah; tetapi sebagai patokan, itu bagus.

Yakk
sumber
1
longjmphanya legal di C untuk melepaskan tumpukan kembali ke setjmpdalam fungsi induk. (Seperti memecah beberapa level sarang, tetapi untuk pemanggilan fungsi alih-alih loop). longjjmpke konteks dari setjmpselesai dalam fungsi yang telah kembali tidak sah (dan saya curiga tidak akan bekerja dalam praktik dalam banyak kasus). Saya tidak akrab dengan rutinitas bersama, tetapi dari uraian Anda tentang rutinitas serupa dengan utas ruang pengguna, saya pikir itu akan membutuhkan tumpukannya sendiri dan juga konteks simpanan-register, dan longjmphanya memberi Anda daftar Hemat, bukan tumpukan yang terpisah.
Peter Cordes
1
Oh, saya seharusnya baru saja googled: fanf.livejournal.com/105413.html menjelaskan membuat ruang stack untuk menjalankan coroutine. (Yang seperti yang saya duga, diperlukan di atas hanya menggunakan setjmp / longjmp).
Peter Cordes
2
@PeterCordes: Implementasi tidak diperlukan untuk menyediakan sarana apa pun yang dengannya kode dapat membuat pasangan jmp_buff yang cocok untuk digunakan sebagai coroutine. Beberapa implementasi menentukan cara melalui mana kode dapat membuat meskipun Standar tidak mengharuskan mereka untuk memberikan kemampuan seperti itu. Saya tidak akan menjelaskan kode yang bergantung pada teknik-teknik seperti "standar C", karena dalam banyak kasus, jmp_buff akan menjadi struktur buram yang tidak dijamin untuk berperilaku konsisten antara kompiler yang berbeda.
supercat
6

Lihatlah kode ini, dari http://www-personal.umich.edu/~axe/research/Software/CC/CC2/TourExec1.1.f.html yang sebenarnya merupakan bagian dari simulasi Dilema Tahanan yang besar. Jika Anda telah melihat kode FORTRAN atau BASIC lama, Anda akan menyadari bahwa itu tidak biasa.

C  Not nice rules in second round of tour (cut and pasted 7/15/93)
   FUNCTION K75R(J,M,K,L,R,JA)
C  BY P D HARRINGTON
C  TYPED BY JM 3/20/79
   DIMENSION HIST(4,2),ROW(4),COL(2),ID(2)
   K75R=JA       ! Added 7/32/93 to report own old value
   IF (M .EQ. 2) GOTO 25
   IF (M .GT. 1) GOTO 10
   DO 5 IA = 1,4
     DO 5 IB = 1,2
5  HIST(IA,IB) = 0

   IBURN = 0
   ID(1) = 0
   ID(2) = 0
   IDEF = 0
   ITWIN = 0
   ISTRNG = 0
   ICOOP = 0
   ITRY = 0
   IRDCHK = 0
   IRAND = 0
   IPARTY = 1
   IND = 0
   MY = 0
   INDEF = 5
   IOPP = 0
   PROB = .2
   K75R = 0
   RETURN

10 IF (IRAND .EQ. 1) GOTO 70
   IOPP = IOPP + J
   HIST(IND,J+1) = HIST(IND,J+1) + 1
   IF (M .EQ. 15 .OR. MOD(M,15) .NE. 0 .OR. IRAND .EQ. 2) GOTO 25
   IF (HIST(1,1) / (M - 2) .GE. .8) GOTO 25
   IF (IOPP * 4 .LT. M - 2 .OR. IOPP * 4 .GT. 3 * M - 6) GOTO 25
   DO 12 IA = 1,4
12 ROW(IA) = HIST(IA,1) + HIST(IA,2)

   DO 14 IB = 1,2
     SUM = .0
     DO 13 IA = 1,4
13   SUM = SUM + HIST(IA,IB)
14 COL(IB) = SUM

   SUM = .0
   DO 16 IA = 1,4
     DO 16 IB = 1,2
       EX = ROW(IA) * COL(IB) / (M - 2)
       IF (EX .LE. 1.) GOTO 16
       SUM = SUM + ((HIST(IA,IB) - EX) ** 2) / EX
16 CONTINUE

   IF (SUM .GT. 3) GOTO 25
   IRAND = 1
   K75R = 1
   RETURN

25 IF (ITRY .EQ. 1 .AND. J .EQ. 1) IBURN = 1
   IF (M .LE. 37 .AND. J .EQ. 0) ITWIN = ITWIN + 1
   IF (M .EQ. 38 .AND. J .EQ. 1) ITWIN = ITWIN + 1
   IF (M .GE. 39 .AND. ITWIN .EQ. 37 .AND. J .EQ. 1) ITWIN = 0
   IF (ITWIN .EQ. 37) GOTO 80
   IDEF = IDEF * J + J
   IF (IDEF .GE. 20) GOTO 90
   IPARTY = 3 - IPARTY
   ID(IPARTY) = ID(IPARTY) * J + J
   IF (ID(IPARTY) .GE. INDEF) GOTO 78
   IF (ICOOP .GE. 1) GOTO 80
   IF (M .LT. 37 .OR. IBURN .EQ. 1) GOTO 34
   IF (M .EQ. 37) GOTO 32
   IF (R .GT. PROB) GOTO 34
32 ITRY = 2
   ICOOP = 2
   PROB = PROB + .05
   GOTO 92

34 IF (J .EQ. 0) GOTO 80
   GOTO 90

70 IRDCHK = IRDCHK + J * 4 - 3
   IF (IRDCHK .GE. 11) GOTO 75
   K75R = 1
   RETURN

75 IRAND = 2
   ICOOP = 2
   K75R = 0
   RETURN

78 ID(IPARTY) = 0
   ISTRNG = ISTRNG + 1
   IF (ISTRNG .EQ. 8) INDEF = 3
80 K75R = 0
   ITRY = ITRY - 1
   ICOOP = ICOOP - 1
   GOTO 95

90 ID(IPARTY) = ID(IPARTY) + 1
92 K75R = 1
95 IND = 2 * MY + J + 1
   MY = K75R
   RETURN
   END

Ada banyak masalah di sini yang melampaui pernyataan GOTO di sini; Jujur saya pikir pernyataan GOTO itu sedikit kambing hitam. Tetapi aliran kontrol sama sekali tidak jelas di sini, dan kode dicampur bersama dengan cara yang membuatnya sangat tidak jelas apa yang terjadi. Bahkan tanpa menambahkan komentar atau menggunakan nama variabel yang lebih baik, mengubahnya ke struktur blok tanpa GOTO akan membuatnya lebih mudah untuk dibaca dan diikuti.

prosfila
sumber
4
sangat benar :-) Mungkin layak untuk disebutkan: warisan FORTAN dan BASIC tidak memiliki struktur blok, sehingga jika klausa LALU tidak dapat bertahan pada satu baris, GOTO adalah satu-satunya alternatif.
Christophe
Label teks alih-alih angka, atau setidaknya komentar pada baris bernomor, akan banyak membantu.
Cees Timmerman
Kembali pada hari FORTRAN-IV saya: Saya membatasi penggunaan GOTO untuk mengimplementasikan blok IF / ELSE IF / ELSE, loop WHILE dan BREAK dan NEXT dalam loop. Seseorang menunjukkan kepada saya kejahatan kode spaghetti dan mengapa Anda harus struktur untuk menghindarinya bahkan jika Anda harus menerapkan struktur blok Anda dengan GOTO. Kemudian saya mulai menggunakan pra-prosesor (RATFOR, IIRC). Goto secara intrinsik tidak jahat, itu hanya konstruksi tingkat rendah yang terlalu kuat yang memetakan ke instruksi cabang assembler. Jika Anda harus menggunakannya karena bahasa Anda kurang, gunakan bahasa itu untuk membangun atau menambah struktur blok yang tepat.
nigel222
@CeesTimmerman: Itu adalah kode taman FORTRAN IV. Label teks tidak didukung dalam FORTRAN IV. Saya tidak tahu apakah versi bahasa yang lebih baru mendukungnya. Komentar pada baris yang sama dengan kode tidak didukung dalam FORTRAN IV standar, meskipun mungkin ada ekstensi khusus vendor untuk mendukung mereka. Saya tidak tahu apa kata standar FORTRAN "saat ini": Saya sudah lama meninggalkan FORTRAN, dan saya tidak ketinggalan. (Kode FORTRAN terbaru yang saya lihat memiliki kemiripan yang kuat dengan PASCAL awal tahun 1970-an.)
John R. Strohm
1
@CeesTimmerman: Ekstensi khusus vendor. Kode pada umumnya BENAR-BENAR malu pada komentar. Selain itu, ada konvensi yang menjadi hal biasa di beberapa tempat, menempatkan nomor baris hanya pada pernyataan LANJUTKAN dan FORMAT, untuk membuatnya lebih mudah untuk menambahkan baris nanti. Kode ini tidak mengikuti konvensi itu.
John R. Strohm
0

Salah satu prinsip pemrograman terpelihara adalah enkapsulasi . Intinya adalah Anda berinteraksi dengan modul / rutin / subrutin / komponen / objek dengan menggunakan antarmuka yang ditentukan, dan hanya antarmuka itu, dan hasilnya akan dapat diprediksi (dengan asumsi bahwa unit tersebut diuji secara efektif).

Dalam satu unit kode, prinsip yang sama berlaku. Jika Anda secara konsisten menerapkan pemrograman terstruktur atau prinsip-prinsip pemrograman berorientasi objek, Anda tidak akan:

  1. buat jalur tak terduga melalui kode
  2. tiba di bagian kode dengan nilai variabel yang tidak ditentukan atau tidak diizinkan
  3. keluar dari jalur kode dengan nilai variabel yang tidak ditentukan atau tidak diizinkan
  4. gagal menyelesaikan unit transaksi
  5. tinggalkan sebagian kode atau data dalam memori yang mati secara efektif, tetapi tidak memenuhi syarat untuk pembersihan dan realokasi sampah, karena Anda belum memberi sinyal pembebasannya menggunakan konstruk eksplisit yang meminta pelepasan mereka ketika jalur kontrol kode keluar dari unit

Beberapa gejala yang lebih umum dari kesalahan pemrosesan ini termasuk kebocoran memori, penimbunan memori, overflow pointer, crash, catatan data tidak lengkap, rekam add / chg / hapus pengecualian, kesalahan halaman memori, dan sebagainya.

Manifestasi yang dapat diamati pengguna dari masalah ini termasuk penguncian antarmuka pengguna, kinerja yang secara bertahap menurun, catatan data yang tidak lengkap, ketidakmampuan untuk memulai atau menyelesaikan transaksi, data yang rusak, pemadaman jaringan, pemadaman listrik, kegagalan sistem tertanam (dari hilangnya kendali rudal) hilangnya pelacakan dan kemampuan kontrol dalam sistem kontrol lalu lintas udara), kegagalan waktu, dan sebagainya. Katalog ini sangat luas.

Jaxter
sumber
3
Anda menjawab tanpa menyebutkan gotosatu kali pun. :)
Robert Harvey
0

goto berbahaya karena biasanya digunakan di tempat yang tidak diperlukan. Menggunakan apa pun yang tidak diperlukan itu berbahaya, tetapi terutama kebagian . Jika Anda google Anda akan menemukan banyak kesalahan di sekitar disebabkan oleh goto, ini bukan alasan untuk tidak menggunakannya (bug selalu terjadi ketika Anda menggunakan fitur bahasa karena itu intrinsik dalam pemrograman), tetapi beberapa dari mereka jelas sangat terkait untuk penggunaan goto .


Alasan menggunakan / tidak menggunakan goto :

  • Jika Anda memerlukan loop, Anda harus menggunakan whileatau for.

  • Jika Anda perlu melakukan lompatan bersyarat, gunakan if/then/else

  • Jika Anda memerlukan prosedur, panggil fungsi / metode.

  • Jika Anda perlu keluar dari suatu fungsi, cukup return.

Saya dapat mengandalkan jari-jari saya tempat-tempat di mana saya telah melihat gotodigunakan dan digunakan dengan benar.

  • CPython
  • libKTX
  • mungkin sedikit lagi

Di libKTX ada fungsi yang memiliki kode berikut

if(something)
    goto cleanup;

if(bla)
    goto cleanup;

cleanup:
    delete [] array;

Sekarang di tempat gotoini berguna karena bahasanya adalah C:

  • kita berada di dalam suatu fungsi
  • kita tidak dapat menulis fungsi pembersihan (karena kita memasuki lingkup lain, dan membuat status fungsi pemanggil yang dapat diakses lebih banyak beban)

Use case ini berguna karena dalam C kita tidak memiliki kelas, jadi cara paling sederhana untuk membersihkan adalah menggunakan a goto.

Jika kami memiliki kode yang sama dalam C ++ tidak perlu lagi untuk goto:

class MyClass{
    public:

    void Function(){
        if(something)
            return Cleanup(); // invalid syntax in C#, but valid in C++
        if(bla)
            return Cleanup(); // invalid syntax in C#, but valid in C++
    }

    // access same members, no need to pass state (compiler do it for us).
    void Cleanup(){

    }



}

Jenis bug apa yang dapat menyebabkannya? Apa pun. Loop tak terbatas, urutan eksekusi salah, tumpukan sekrup ..

Kasing terdokumentasi adalah kerentanan dalam SSL yang memungkinkan Manusia dalam serangan tengah yang disebabkan oleh penggunaan goto yang salah: inilah artikelnya

Itu kesalahan ketik, tetapi tidak diketahui untuk sementara waktu, jika kode disusun dengan cara lain, diuji dengan benar kesalahan seperti itu tidak mungkin terjadi.

GameDeveloper
sumber
2
Ada banyak komentar untuk satu jawaban yang menjelaskan dengan sangat jelas bahwa penggunaan "goto" benar-benar tidak sesuai dengan bug SSL - bug itu disebabkan oleh duplikasi satu baris kode yang ceroboh, sehingga pernah dieksekusi secara kondisional, dan sekali tanpa syarat.
gnasher729
Ya saya sedang menunggu contoh sejarah yang lebih baik dari bug goto sebelum saya menerimanya. Seperti Yang Dikatakan; Tidak masalah apa yang ada di baris kode itu; Kurangnya kurung kurawal akan mengeksekusinya dan menyebabkan kesalahan. Saya ingin tahu; apa itu "Stack Screw"?
Akiva
1
Contoh dari kode yang saya kerjakan sebelumnya di PL / 1 CICS. Program mengeluarkan layar yang terdiri dari peta garis tunggal. Ketika layar dikembalikan, ia menemukan array peta yang telah dikirim. Menggunakan elemen-elemen itu untuk menemukan indeks dalam satu array, dan kemudian menggunakan indeks itu ke indeks variabel array untuk melakukan GOTO sehingga dapat memproses peta individu itu. Jika larik peta yang dikirim salah (atau rusak) maka ia dapat mencoba melakukan GOTO ke label yang salah, atau kerusakan yang lebih buruk karena mengakses elemen setelah akhir larik variabel label. Ditulis ulang untuk menggunakan sintaks jenis kasus.
Kickstart