Banyak program memerlukan kumpulan pilihan yang tetap, misalnya hari dalam seminggu atau status sebuah pekerjaan. enum mendeklarasikan konstanta bernama dengan nilai bilangan bulat yang disusun otomatis oleh kompiler, sehingga kode membaca nama yang bermakna dan bukan angka yang harus dihafal. Topik ini membahas definisi enum, nilai yang berada di balik setiap namanya, penyesuaian nilai awal, serta pemakaiannya dalam pernyataan switch.
Mendefinisikan enum#
Definisi enum dimulai dengan kata kunci enum, diikuti tag dan daftar nama di dalam kurung kurawal. Kompiler menomori nama-nama itu secara berurutan dimulai dari 0, dan setiap nama berikutnya bernilai satu lebih besar dari nama sebelumnya. Variabel enum dideklarasikan dengan bentuk enum Tag namaVariabel; dan nilainya disimpan sebagai bilangan bulat.
#include <stdio.h>
enum Hari {
SENIN,
SELASA,
RABU,
KAMIS,
JUMAT,
SABTU,
MINGGU
};
enum Bulan {
JANUARI = 1,
FEBRUARI,
MARET,
APRIL,
MEI,
JUNI,
JULI,
AGUSTUS,
SEPTEMBER,
OKTOBER,
NOVEMBER,
DESEMBER
};
int main(void) {
enum Hari libur = MINGGU;
printf("SENIN = %d\n", SENIN);
printf("KAMIS = %d\n", KAMIS);
printf("MINGGU = %d\n", MINGGU);
printf("libur = %d\n", libur);
printf("DESEMBER = %d\n", DESEMBER);
return 0;
}SENIN = 0
KAMIS = 3
MINGGU = 6
libur = 6
DESEMBER = 12Keluaran memperlihatkan nilai di balik setiap nama. SENIN bernilai 0 karena menjadi nama pertama, KAMIS bernilai 3 karena berjarak tiga langkah darinya, dan MINGGU bernilai 6. Variabel libur menyimpan nilai yang sama dengan MINGGU karena diinisialisasi dari namanya. Definisi kedua menetapkan JANUARI = 1, sehingga nama-nama sesudahnya berlanjut menjadi 2 sampai 12 dan DESEMBER jatuh pada 12. Penomoran yang cocok dengan kebiasaan penulisan tanggal semacam ini merupakan alasan nilai awal kustom sering dipakai.
Nama konstanta enum berbagi ruang nama dengan variabel dan fungsi pada lingkup yang sama. Dua enum yang masing-masing memiliki nama AKTIF akan bertabrakan saat dikompilasi, dan penugasan nama yang sudah dipakai variabel juga ditolak kompiler. Karena itu nama enum biasanya diberi awalan yang menunjuk kelompoknya, misalnya STATUS_ atau HARI_, supaya nama-nama itu tetap unik seiring bertambahnya kode.
Enum juga dapat dideklarasikan tanpa nama apabila yang dibutuhkan hanyalah konstantanya.
// tidak-dijalankan
enum { MAKS_NAMA = 32, MAKS_BARIS = 80 };Kedua konstanta pada contoh di atas dapat dipakai di mana pun nilai int diterima, misalnya sebagai ukuran array. Bentuk ini menjadi alternatif #define untuk konstanta bilangan bulat karena penulisannya lebih ringkas dan tetap terlihat oleh debugger.
enum sebagai indeks array#
Karena nilai enum berupa bilangan berurutan, enum sering dipakai sebagai indeks array. Nama hari menjadi nomor indeksnya, sedangkan array menyimpan teks yang ditampilkan. Satu nama tambahan pada ujung enum, yaitu JUMLAH_HARI, otomatis bernilai jumlah seluruh harinya. Nilai itu menjadi batas atas perulangan dan ikut bertambah apabila daftar hari diperluas.
#include <stdio.h>
enum Hari {
SENIN,
SELASA,
RABU,
KAMIS,
JUMAT,
SABTU,
MINGGU,
JUMLAH_HARI
};
int main(void) {
const char *nama[7] = {
"Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"
};
int i;
for (i = SENIN; i < JUMLAH_HARI; i = i + 1) {
printf("%d %s\n", i, nama[i]);
}
return 0;
}0 Senin
1 Selasa
2 Rabu
3 Kamis
4 Jumat
5 Sabtu
6 MingguPerulangan bergerak dari SENIN sampai batas JUMLAH_HARI, sehingga setiap indeks array terpakai dan tidak ada elemen yang terlewat. Apabila sebuah hari ditambahkan ke dalam enum sebelum JUMLAH_HARI, nilai batas itu naik sendiri dan perulangannya tidak perlu disunting. Pola ini mengurangi kebutuhan angka ajaib pada kode yang memetakan konstanta ke teks atau data lain, dan penomorannya yang berurutan membuat pemetaan semacam itu mudah diperiksa. Array nama bertipe const char * karena isinya berupa teks tetap yang tidak diubah sepanjang program berjalan.
enum dalam switch#
Pernyataan switch merupakan pasangan yang paling alami bagi enum, karena setiap nama enum menjadi label case yang bermakna. Percabangannya mudah dibaca, dan kompiler dapat membantu memeriksa kelengkapannya. Opsi -Wall pada gcc mengaktifkan pemeriksaan -Wswitch yang melaporkan nilai enum yang belum ditangani oleh switch mana pun. Bila pemeriksaan itu ingin dimanfaatkan, label default sengaja ditunda sampai seluruh nilai memang tertangani. Kehadiran default membuat kompiler menganggap switch sudah lengkap, sehingga cabang yang terlewat tidak lagi dilaporkan.
#include <stdio.h>
enum Status {
BELUM,
PROSES,
SELESAI
};
void tampilkan(enum Status s) {
switch (s) {
case BELUM:
printf("Menunggu dikerjakan\n");
break;
case PROSES:
printf("Sedang dikerjakan\n");
break;
case SELESAI:
printf("Selesai dikerjakan\n");
break;
}
}
int main(void) {
enum Status tugas[3] = {SELESAI, BELUM, PROSES};
int i;
for (i = 0; i < 3; i = i + 1) {
tampilkan(tugas[i]);
}
return 0;
}Selesai dikerjakan
Menunggu dikerjakan
Sedang dikerjakanFungsi tampilkan menerima satu enum Status dan memilih pesan melalui switch. Setiap case menuliskan nama konstantanya dan bukan angkanya, sehingga maksud setiap cabang terbaca tanpa menghafal nilai. Label default tidak ditulis karena ketiga nilai enum sudah tertangani, dan apabila enum kelak diperluas, -Wswitch akan melaporkan cabang yang terlewat sebelum program dijalankan.
Kesalahan umum#
Variabel enum tidak membatasi nilainya pada daftar namanya. Penugasan hari = 99 dikompilasi tanpa peringatan karena enum diperlakukan sebagai bilangan bulat, lalu switch tanpa label default akan melewati semua cabangnya tanpa pesan apa pun. Menyertakan label default atau memeriksa rentang nilai sebelum digunakan menjaga program tetap menangani masukan yang tak terduga.
Kekeliruan kedua adalah mengira nama enum bertipe khusus yang terpisah. Nilai di baliknya merupakan konstanta int biasa, sehingga dapat dicetak dengan %d, dibandingkan dengan bilangan, dan dioper ke fungsi yang menerima int. Mengetahui hal ini penting saat membaca pesan error maupun keluaran program yang menampilkan nilainya.
Kekeliruan ketiga adalah membiarkan perulangan berjalan sampai nilai terakhir enum tanpa batas tambahan. Perulangan yang berhenti pada MINGGU tetap benar, tetapi batas yang ditulis dengan angka seperti i < 7 berpotensi usang saat enum diperluas. Menyediakan nama penutup seperti JUMLAH_HARI menjaga batas perulangan selaras dengan daftarnya.
Ringkasan#
- enum mendeklarasikan konstanta bernama yang diberi nomor berurutan secara otomatis dimulai dari 0.
- Nilai awal dapat ditetapkan secara manual, dan nama-nama sesudahnya berlanjut satu per satu.
- enum tanpa nama menjadi kumpulan konstanta bernama untuk kebutuhan seperti ukuran array.
- Pasangan enum dan switch menghasilkan percabangan yang terbaca, dan -Wswitch melaporkan nilai yang belum ditangani.
- Nama penutup seperti JUMLAH_HARI menjadikan enum berguna sebagai indeks array sekaligus batas perulangan yang ikut menyesuaikan.
- Variabel enum disimpan sebagai int dan tidak membatasi nilai yang diberikan kepadanya.
Referensi#
- enum specifier — Cppreference — Kaidah deklarasi enum, penomoran otomatis, dan nilai awal kustom.
- Warning Options — GCC, the GNU Compiler Collection — Daftar opsi peringatan gcc, termasuk -Wswitch untuk nilai enum yang belum ditangani.