Pengujian satu nilai terhadap sejumlah kemungkinan tetap dapat ditulis dengan switch, yang melompat langsung ke label case yang cocok tanpa menguji kondisi satu per satu. Topik ini membahas struktur switch dan case, perilaku fall-through ketika break tidak ditulis, peran label default, serta pertimbangan memilih switch dibanding rantai if. Seluruh contoh berupa program utuh yang dikompilasi dengan g++ pada standar C++17 beserta keluaran aslinya.
Struktur switch dan case#
Pernyataan switch menguji satu ekspresi bertipe bilangan bulat, seperti int atau char, kemudian melompat ke label case yang nilainya sama dengan hasil ekspresi itu. Nilai label wajib berupa konstanta yang diketahui saat kompilasi, sehingga variabel biasa tidak dapat menjadi label. Eksekusi dimulai dari label yang cocok dan berlanjut sampai break menghentikan switch atau akhir blok tercapai. Apabila tidak ada label yang cocok dan label default ditulis, eksekusi berpindah ke label tersebut. Bentuk ini menggantikan rantai panjang else if yang semuanya membandingkan variabel yang sama dengan nilai tetap.
Program berikut menerjemahkan nomor hari menjadi namanya. break pada akhir setiap case menjaga agar case berikutnya tidak ikut terjalankan, sedangkan default menangani nomor di luar 1 sampai 7. Susunan label yang berurutan seperti ini mudah dibaca karena setiap nilai tetap memiliki jalurnya sendiri.
#include <iostream>
int main() {
int nomorHari = 3;
switch (nomorHari) {
case 1:
std::cout << "Senin\n";
break;
case 2:
std::cout << "Selasa\n";
break;
case 3:
std::cout << "Rabu\n";
break;
case 4:
std::cout << "Kamis\n";
break;
case 5:
std::cout << "Jumat\n";
break;
case 6:
std::cout << "Sabtu\n";
break;
case 7:
std::cout << "Minggu\n";
break;
default:
std::cout << "Nomor hari tidak valid\n";
break;
}
return 0;
}RabuNilai nomorHari bernilai 3, sehingga eksekusi melompat langsung ke label case 3: dan mencetak Rabu sebelum break menghentikannya. Pembandingan yang dilakukan switch berupa kesamaan, bukan rentang, sehingga kebutuhan seperti menguji nomor di atas 5 dinyatakan lewat default atau di luar switch. Karakter juga dapat diuji dengan cara yang sama karena char termasuk tipe bilangan bulat.
Perilaku fall-through#
Tanpa break, eksekusi tidak berhenti di akhir suatu case, melainkan meneruskan pernyataan pada case berikutnya. Perilaku ini disebut fall-through dan kebanyakan merupakan kekeliruan, tetapi dapat dimanfaatkan dengan sengaja ketika beberapa nilai membutuhkan penanganan yang sama. Bentuk yang paling aman adalah label yang berjejer tanpa pernyataan di antaranya, karena tidak ada baris yang terlewat secara keliru. Pola label berjejer ini lazim untuk pengelompokan nilai, sebagaimana perhitungan jumlah hari pada setiap bulan.
Program berikut mengelompokkan bulan dengan 31 hari dan 30 hari, sedangkan Februari ditangani tersendiri. Tujuh label jatuh ke pernyataan yang sama, sehingga tidak ada duplikasi pernyataan cetak di antara kelompoknya.
#include <iostream>
int main() {
int bulan = 7;
switch (bulan) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
std::cout << "31 hari\n";
break;
case 4:
case 6:
case 9:
case 11:
std::cout << "30 hari\n";
break;
case 2:
std::cout << "28 atau 29 hari\n";
break;
default:
std::cout << "Bulan tidak valid\n";
break;
}
return 0;
}31 hariBentuk fall-through lain sengaja menjalankan sebagian pernyataan sebelum jatuh ke label berikutnya. C++17 menyediakan atribut [[fallthrough]] yang menandai maksud tersebut secara eksplisit sekaligus mencegah munculnya peringatan compiler. Program berikut menyusun rangkaian kerja kebersihan, yaitu tingkat tertinggi mengerjakan semua langkah, sedangkan tingkat yang lebih rendah mengerjakan sebagiannya.
#include <iostream>
int main() {
int tingkat = 2;
switch (tingkat) {
case 3:
std::cout << "mengepel lantai\n";
[[fallthrough]];
case 2:
std::cout << "menyapu lantai\n";
[[fallthrough]];
case 1:
std::cout << "membuang sampah\n";
break;
default:
std::cout << "tingkat tidak dikenal\n";
break;
}
return 0;
}menyapu lantai
membuang sampahTingkat 2 menghasilkan dua baris karena eksekusi dimulai pada case 2:, mencetak penyapuan lantai, kemudian jatuh ke case 1: tanpa break. Atribut [[fallthrough]] tidak mengubah alur program sama sekali, melainkan mendokumentasikan bahwa jatuhnya memang disengaja. Pembaca kode berikutnya pun tidak perlu menduga adanya break yang terlupakan.
default dan pemilihan switch atau if#
Label default menangani nilai yang tidak cocok dengan label case mana pun, sehingga kasus yang tidak terduga tetap mendapat perlakuan yang jelas. Letaknya bebas di dalam blok switch, tetapi posisi terakhir disertai break merupakan kebiasaan yang paling mudah dibaca. Tanpa default, nilai di luar semua label hanya membuat switch tidak melakukan apa pun, dan hal itu mungkin memang dimaksudkan atau justru kelalaian.
Perbandingan ciri kedua pendekatan diringkas pada tabel berikut. Baris terakhirnya menjadi alasan utama memilih switch ketika nilainya banyak dan tetap.
| Aspek | switch | Rantai if-else |
|---|---|---|
| Tipe nilai yang diuji | Bilangan bulat dan tipe turunannya | Ekspresi bool apa pun |
| Bentuk label | Konstanta yang diketahui saat kompilasi | Ekspresi bebas, termasuk rentang |
| Cara memilih jalur | Lompatan langsung ke label yang cocok | Diuji berurutan dari atas ke bawah |
| Penulisan banyak nilai tetap | Ringkas pada satu blok | Memanjang pada setiap tambahan nilai |
Sebagai kaidah praktis, switch dipilih ketika satu nilai dibandingkan dengan sejumlah kemungkinan tetap, seperti nomor bulan atau pilihan menu. Rantai if-else dipilih ketika kondisinya berupa rentang, menggabungkan beberapa variabel, atau bertipe selain bilangan bulat seperti std::string. Perbedaan kinerja antara keduanya umumnya tidak berarti bagi program kecil, sehingga keterbacaan menjadi penentu utama pilihannya.
Kesalahan umum#
Tiga kekeliruan berikut paling sering muncul pada pemakaian switch. Semuanya dapat dicegah dengan kebiasaan penulisan yang tetap.
breakyang terlupakan pada akhircase. Eksekusi jatuh kecaseberikutnya tanpa pesan error, dan hasilnya berupa logika yang salah secara diam-diam. Tulisbreakpada akhir setiapcase, atau letakkan atribut[[fallthrough]]apabila jatuhnya memang disengaja.- Deklarasi variabel di dalam
casetanpa tanda kurung kurawal. Compiler menolak programnya karena terdapat jalur lompatan yang dapat melewati inisialisasi variabel tersebut. Bungkus isicasedengan{ }atau pindahkan deklarasinya ke sebelumswitch. switchterhadapstd::string. Tipe string bukan bilangan bulat, sehingga programnya tidak dapat dikompilasi. Gunakan rantaiif-elseatau tabel pemetaan sepertistd::mapuntuk kasus tersebut.
Ketiga pola di atas berbagi satu sifat, yaitu muncul tanpa peringatan saat penulisan berlangsung cepat. Sebagian besar kesalahan tersebut tertangkap dengan membaca ulang setiap case dan memeriksa satu hal sederhana, yaitu apakah jalur keluarnya jelas.
Ringkasan#
switchmelompat ke labelcasebernilai sama, dengan label yang wajib berupa konstanta bertipe bilangan bulat.- Tanpa
break, eksekusi jatuh kecaseberikutnya, label yang berjejer menjadi pola pengelompokan yang sah, dan[[fallthrough]]menandai jatuh yang disengaja. defaultmenangani nilai di luar semua label, sedangkan rantaiif-elselebih cocok untuk rentang dan kondisi campuran.
Referensi#
- switch statement — cppreference.com
— Kaidah formal
switch,case, dandefaultbeserta batasan tipenya. - Switch statement basics — Learn C++
— Pengantar
switchmulai dari konstanta label sampaidefault. - Switch fallthrough and scoping — Learn C++
— Rincian fall-through, deklarasi variabel, dan lingkup di dalam
case.