Organisasi kami memiliki aturan pengkodean yang diperlukan (tanpa penjelasan apa pun) bahwa:
if… else if konstruksi harus diakhiri dengan klausa else
Contoh 1:
if ( x < 0 )
{
x = 0;
} /* else not needed */
Contoh 2:
if ( x < 0 )
{
x = 0;
}
else if ( y < 0 )
{
x = 3;
}
else /* this else clause is required, even if the */
{ /* programmer expects this will never be reached */
/* no change in value of x */
}
Kasus tepi apa yang dirancang untuk ditangani ini?
Yang juga menjadi perhatian saya tentang alasannya adalah bahwa Contoh 1 tidak memerlukan else
tetapi Contoh 2 membutuhkannya . Jika alasannya adalah dapat digunakan kembali dan diperpanjang, saya pikir else
harus digunakan dalam kedua kasus tersebut.
assert(false, "should never go here")
mungkin masuk akalif (x < 0) { x = 0; } else { if (y < 0) { x = 3; }}
. Atau Anda bisa saja mengikuti aturan seperti itu, banyak di antaranya bodoh, hanya karena Anda diharuskan.< 0
pemeriksaan), sehingga assert akan untuk menghentikan program pada kasus yang mungkin paling umum terjadi di mana nilai berada dalam batas yang diharapkan.Jawaban:
Seperti disebutkan dalam jawaban lain, ini dari pedoman pengkodean MISRA-C. Tujuannya adalah pemrograman defensif, sebuah konsep yang sering digunakan dalam pemrograman kritis-misi.
Artinya, setiap
if - else if
harus diakhiri denganelse
, dan setiapswitch
harus diakhiri dengan adefault
.Ada dua alasan untuk ini:
Kode yang mendokumentasikan sendiri. Jika Anda menulis
else
tetapi membiarkannya kosong itu berarti: "Saya telah mempertimbangkan skenario ketika tidakif
dan juga tidakelse if
benar".Tidak menulis di
else
sana berarti: "baik saya mempertimbangkan skenario di mana tidakif
jugaelse if
benar, atau saya benar-benar lupa untuk mempertimbangkannya dan berpotensi ada bug gemuk di sini dalam kode saya".Hentikan kode pelarian. Dalam perangkat lunak misi kritis, Anda perlu menulis program yang kuat yang memperhitungkan bahkan untuk yang sangat tidak mungkin. Jadi Anda bisa melihat kode seperti
if (mybool == TRUE) { } else if (mybool == FALSE) { } else { // handle error }
Kode ini akan benar-benar asing bagi pemrogram PC dan ilmuwan komputer, tetapi sangat masuk akal dalam perangkat lunak misi kritis, karena kode ini menangkap kasus di mana "mybool" telah rusak, untuk alasan apa pun.
Secara historis, Anda akan takut kerusakan memori RAM karena EMI / noise. Ini tidak banyak menjadi masalah hari ini. Jauh lebih mungkin, kerusakan memori terjadi karena bug di tempat lain dalam kode: penunjuk ke lokasi yang salah, bug array-out-of-bounds, stack overflow, kode pelarian, dll.
Jadi sebagian besar waktu, kode seperti ini kembali untuk menampar wajah Anda sendiri ketika Anda telah menulis bug selama tahap implementasi. Artinya, ini juga dapat digunakan sebagai teknik debug: program yang Anda tulis memberi tahu Anda saat Anda menulis bug.
EDIT
Mengenai mengapa
else
tidak diperlukan setelah setiapif
:Sebuah
if-else
atauif-else if-else
seluruhnya mencakup semua kemungkinan nilai yang dapat dimiliki variabel. Tetapiif
pernyataan sederhana tidak selalu ada untuk mencakup semua kemungkinan nilai, itu memiliki penggunaan yang jauh lebih luas. Paling sering Anda hanya ingin memeriksa kondisi tertentu dan jika tidak terpenuhi, maka jangan lakukan apa pun. Maka tidak ada artinya menulis program defensif untuk menutupielse
kasus ini.Ditambah itu akan mengacaukan kode sepenuhnya jika Anda menulis kosong
else
setelah setiapif
.MISRA-C: 2012 15.7 tidak memberikan alasan mengapa
else
tidak diperlukan, hanya menyatakan:sumber
if/else if/else
dikompilasi sesuai dengan yang Anda harapkan? Dan satu lagi untuk memverifikasi pemverifikasi sebelumnya juga?mybool
memiliki tipe non-boolean, seperti yang terjadi sebelum C mendapatkannya sendiribool
; maka compiler tidak akan membuat asumsi tanpa analisis statis tambahan). Dan pada subjek 'Jika Anda menulis yang lain tetapi membiarkannya kosong, itu berarti: "Saya telah mempertimbangkan skenario ketika tidak jika atau yang lain jika benar".': Reaksi pertama saya adalah menganggap programmer lupa memasukkan kode blok else, jika tidak, mengapa blok else kosong hanya ada di sana? Sebuah// unused
komentar akan sesuai, bukan hanya sebuah blok kosong.else
blok tersebut perlu berisi semacam komentar jika tidak ada kode. Praktik umum bagi kosongelse
adalah titik koma tunggal ditambah komentar:else { ; // doesn't matter }
. Karena tidak ada alasan mengapa ada orang yang hanya mengetikkan titik koma tunggal yang menjorok ke dalam barisnya sendiri. Praktek yang serupa kadang-kadang digunakan dalam loop kosong:while(something) { ; // do nothing }
. (kode dengan jeda baris, jelas. komentar SO tidak mengizinkan mereka)Perusahaan Anda mengikuti panduan pengkodean MISRA. Ada beberapa versi pedoman ini yang berisi aturan ini, tetapi dari MISRA-C: 2004 † :
Dalam MISRA-C: 2012 , yang menggantikan versi 2004 dan merupakan rekomendasi saat ini untuk proyek baru, aturan yang sama ada tetapi diberi nomor 15,7 .
Contoh 1: dalam satu pernyataan if programmer mungkin perlu memeriksa n jumlah kondisi dan melakukan operasi tunggal.
if(condition_1 || condition_2 || ... condition_n) { //operation_1 }
Dalam penggunaan biasa melakukan suatu operasi tidak diperlukan setiap saat saat
if
digunakan.Contoh 2: Di sini pemrogram memeriksa n jumlah kondisi dan melakukan beberapa operasi. Dalam penggunaan biasa
if..else if
sepertiswitch
Anda mungkin perlu melakukan operasi seperti default. Jadi penggunaanelse
diperlukan sesuai standar misraif(condition_1 || condition_2 || ... condition_n) { //operation_1 } else if(condition_1 || condition_2 || ... condition_n) { //operation_2 } .... else { //default cause }
† Versi saat ini dan yang lalu dari publikasi ini tersedia untuk dibeli melalui toko web MISRA ( melalui ).
sumber
else
klausa tersebut tidak dapat dijangkau? (Tinggalkan kondisi terakhir sebagai gantinya,Tambahan lain ini akan Mengurangi cakupan kode program Anda.
Dalam pengalaman saya dengan mem-port kernel linux, atau kode android ke platform yang berbeda sering kali kami melakukan kesalahan dan di logcat kami melihat beberapa kesalahan seperti
if ( x < 0 ) { x = 0; } else if ( y < 0 ) { x = 3; } else /* this else clause is required, even if the */ { /* programmer expects this will never be reached */ /* no change in value of x */ printk(" \n [function or module name]: this should never happen \n"); /* It is always good to mention function/module name with the logs. If you end up with "this should never happen" message and the same message is used in many places in the software it will be hard to track/debug. */ }
sumber
__FILE__
dan__LINE__
makro berguna untuk membuat lokasi sumber mudah ditemukan jika pesan pernah dicetak.Hanya penjelasan singkat, karena saya melakukan ini semua sekitar 5 tahun yang lalu.
Ada (dengan sebagian besar bahasa) tidak ada persyaratan sintaksis untuk menyertakan
else
pernyataan "null" (dan tidak perlu{..}
), dan dalam "program kecil sederhana" tidak perlu. Tetapi programmer sejati tidak menulis "program kecil yang sederhana", dan, sama pentingnya, mereka tidak menulis program yang akan digunakan sekali dan kemudian dibuang.Ketika seseorang menulis if / else:
if(something) doSomething; else doSomethingElse;
semuanya tampak sederhana dan orang hampir tidak melihat titik penambahan
{..}
.Tetapi suatu hari, beberapa bulan dari sekarang, beberapa programmer lain (Anda tidak akan pernah membuat kesalahan seperti itu!) Perlu "meningkatkan" program dan akan menambahkan pernyataan.
if(something) doSomething; else doSomethingIForgot; doSomethingElse;
Tiba-tiba
doSomethingElse
agak lupa bahwa seharusnya ada dielse
kaki.Jadi, Anda adalah programmer kecil yang baik dan selalu menggunakannya
{..}
. Tapi Anda menulis:if(something) { if(anotherThing) { doSomething; } }
Semuanya baik-baik saja sampai anak baru itu membuat modifikasi tengah malam:
if(something) { if(!notMyThing) { if(anotherThing) { doSomething; } else { dontDoAnything; // Because it's not my thing. }} }
Ya, ini tidak diformat dengan benar, tetapi begitu juga setengah kode dalam proyek, dan "pemformat otomatis" akan tercampur oleh semua
#ifdef
pernyataan. Dan, tentu saja, kode sebenarnya jauh lebih rumit daripada contoh mainan ini.Sayangnya (atau tidak), saya telah keluar dari hal semacam ini selama beberapa tahun sekarang, jadi saya tidak memiliki contoh "nyata" yang segar dalam pikiran - di atas (jelas) dibuat-buat dan sedikit tipu.
sumber
Ini, dilakukan untuk membuat kode lebih mudah dibaca, untuk referensi di kemudian hari dan untuk memperjelas, kepada peninjau kemudian, bahwa kasus yang tersisa ditangani oleh yang terakhir
else
, adalah kasus tidak melakukan apa-apa , sehingga mereka tidak terlewatkan entah bagaimana pada pandangan pertama.Ini adalah praktik pemrograman yang baik, yang membuat kode dapat digunakan kembali dan diperluas .
sumber
Saya ingin menambahkan - dan sebagian bertentangan - jawaban sebelumnya. Meskipun sudah pasti umum untuk menggunakan if-else if dengan cara yang seperti sakelar yang harus mencakup seluruh rentang nilai yang dapat dipikirkan untuk sebuah ekspresi, itu sama sekali tidak dijamin bahwa berbagai kondisi yang mungkin tercakup sepenuhnya. Hal yang sama dapat dikatakan tentang konstruksi sakelar itu sendiri, oleh karena itu persyaratan untuk menggunakan klausa default, yang menangkap semua nilai yang tersisa dan dapat, jika tidak diperlukan, digunakan sebagai pengaman pernyataan.
Pertanyaan itu sendiri menampilkan contoh balasan yang baik: Kondisi kedua tidak berhubungan dengan x sama sekali (itulah alasan mengapa saya sering lebih memilih varian berbasis if yang lebih fleksibel daripada varian berbasis sakelar). Dari contoh tersebut terlihat jelas bahwa jika kondisi A terpenuhi, x harus diset ke nilai tertentu. Jika A tidak terpenuhi, maka kondisi B diuji. Jika terpenuhi, maka x harus menerima nilai lain. Jika A atau B tidak terpenuhi, maka x harus tetap tidak berubah.
Di sini kita dapat melihat bahwa cabang else kosong harus digunakan untuk mengomentari maksud pemrogram untuk pembaca.
Di sisi lain, saya tidak bisa melihat mengapa harus ada klausul lain terutama untuk pernyataan if yang terbaru dan terdalam. Di C, tidak ada yang namanya 'else if'. Hanya ada jika dan lainnya. Sebaliknya, menurut MISRA, konstruksi harus secara formal diindentasi dengan cara ini (dan saya harus meletakkan kurung kurawal buka pada garis mereka sendiri, tetapi saya tidak suka itu):
if (A) { // do something } else { if (B) { // do something else (no pun intended) } else { // don't do anything here } }
Ketika MISRA meminta untuk memasang kurung kurawal di setiap cabang, maka hal itu bertentangan dengan dirinya sendiri dengan menyebutkan "jika ... lain jika membangun".
Siapapun bisa membayangkan keburukan pohon yang sangat bersarang, lihat di sini di catatan samping . Sekarang bayangkan bahwa konstruksi ini dapat diperluas secara sewenang-wenang di mana saja. Kemudian meminta klausa lain pada akhirnya, tetapi tidak di tempat lain, menjadi tidak masuk akal.
if (A) { if (B) { // do something } // you could to something here } else { // or here if (B) { // or C? // do something else (no pun intended) } else { // don't do anything here, if you don't want to } // what if I wanted to do something here? I need brackets for that. }
Jadi saya yakin bahwa orang-orang yang mengembangkan pedoman MISRA memiliki keinginan untuk beralih-seperti-jika-jika-niat.
Pada akhirnya, mereka harus menentukan dengan tepat apa yang dimaksud dengan "jika ... lain jika membangun"
sumber
Alasan dasarnya mungkin adalah cakupan kode dan hal lain yang tersirat: bagaimana kode akan berperilaku jika kondisinya tidak benar? Untuk pengujian yang asli, Anda memerlukan cara untuk melihat bahwa Anda telah diuji dengan kondisi salah. Jika setiap kasus uji yang Anda miliki melalui klausa if, kode Anda dapat mengalami masalah di dunia nyata karena kondisi yang tidak Anda uji.
Namun, beberapa kondisi mungkin benar seperti Contoh 1, seperti pada pengembalian pajak: "Jika hasilnya kurang dari 0, masukkan 0." Anda masih perlu menjalani tes jika kondisinya salah.
sumber
Secara logis, pengujian apa pun menyiratkan dua cabang. Apa yang Anda lakukan jika itu benar, dan apa yang Anda lakukan jika itu salah.
Untuk kasus di mana salah satu cabang tidak memiliki fungsionalitas, masuk akal untuk menambahkan komentar tentang mengapa tidak perlu memiliki fungsionalitas.
Ini mungkin bermanfaat bagi pemrogram pemeliharaan berikutnya. Mereka tidak perlu mencari terlalu jauh untuk memutuskan apakah kodenya benar. Anda bisa seperti Prehunt the Elephant .
Secara pribadi, ini membantu saya karena memaksa saya untuk melihat kasus lain, dan mengevaluasinya. Ini mungkin merupakan kondisi yang tidak mungkin, dalam hal ini saya dapat mengeluarkan pengecualian karena kontrak dilanggar. Mungkin tidak berbahaya, dalam hal ini komentar sudah cukup.
Jarak tempuh Anda mungkin berbeda.
sumber
Seringkali ketika Anda hanya memiliki satu
if
pernyataan, itu mungkin salah satu alasan seperti:Contoh
void print (char * text) { if (text == null) return; // guard check printf(text); }
Tetapi ketika Anda melakukannya
if .. else if
, itu mungkin salah satu alasan seperti:Dan jika Anda
if .. else if
mencakup semua kemungkinan, dalam hal ini yang terakhirif (...)
tidak diperlukan, Anda dapat menghapusnya, karena pada saat itu satu-satunya nilai yang mungkin adalah nilai yang dicakup oleh kondisi itu.Contoh
int absolute_value (int n) { if (n == 0) { return 0; } else if (n > 0) { return n; } else /* if (n < 0) */ // redundant check { return (n * (-1)); } }
Dan di sebagian besar alasan ini, mungkin ada sesuatu yang tidak sesuai dengan kategori mana pun di Anda
if .. else if
, sehingga kebutuhan untuk menanganinya dalamelse
klausa terakhir , penanganan dapat dilakukan melalui prosedur tingkat bisnis, pemberitahuan pengguna, mekanisme kesalahan internal, ..etc.Contoh
#DEFINE SQRT_TWO 1.41421356237309504880 #DEFINE SQRT_THREE 1.73205080756887729352 #DEFINE SQRT_FIVE 2.23606797749978969641 double square_root (int n) { if (n > 5) return sqrt((double)n); else if (n == 5) return SQRT_FIVE; else if (n == 4) return 2.0; else if (n == 3) return SQRT_THREE; else if (n == 2) return SQRT_TWO; else if (n == 1) return 1.0; else if (n == 0) return 0.0; else return sqrt(-1); // error handling }
else
Klausa terakhir ini sangat mirip dengan beberapa hal lain dalam bahasa sepertiJava
danC++
, seperti:default
kasus dalam pernyataan switchcatch(...)
yang muncul setelah semuacatch
blok tertentufinally
dalam klausa coba-tangkapsumber
Perangkat lunak kami tidak penting untuk misi, namun kami juga memutuskan untuk menggunakan aturan ini karena pemrograman defensif. Kami menambahkan pengecualian lemparan ke kode yang secara teoritis tidak dapat dijangkau (switch + if-else). Dan itu menyelamatkan kami berkali-kali karena perangkat lunak gagal dengan cepat misalnya ketika tipe baru telah ditambahkan dan kami lupa untuk mengubah satu-atau-dua if-else atau switch. Sebagai bonus, masalah ini menjadi sangat mudah ditemukan.
sumber
Nah, contoh saya melibatkan perilaku yang tidak terdefinisi, tetapi terkadang beberapa orang mencoba menjadi mewah dan gagal, lihat:
int a = 0; bool b = true; uint8_t* bPtr = (uint8_t*)&b; *bPtr = 0xCC; if(b == true) { a += 3; } else if(b == false) { a += 5; } else { exit(3); }
Anda mungkin tidak akan pernah berharap untuk memiliki
bool
yang bukantrue
ataufalse
, bagaimanapun itu mungkin terjadi. Secara pribadi saya percaya ini adalah masalah yang disebabkan oleh orang yang memutuskan untuk melakukan sesuatu yang mewah, tetapielse
pernyataan tambahan dapat mencegah masalah lebih lanjut.sumber
Saya saat ini bekerja dengan PHP. Membuat formulir pendaftaran dan formulir login. Saya hanya menggunakan if dan else. Tidak ada lagi jika atau apapun yang tidak perlu.
Jika pengguna mengklik tombol kirim -> ini akan masuk ke pernyataan if berikutnya ... jika nama pengguna kurang dari jumlah karakter 'X' maka waspada. Jika berhasil maka periksa panjang kata sandi dan seterusnya.
Tidak perlu kode tambahan seperti yang lain jika itu dapat menghilangkan keandalan waktu buka server untuk memeriksa semua kode tambahan.
sumber