Program sering memakai nilai tetap yang tidak boleh berubah—misalnya nilai Pi (3.14159), jumlah maksimum elemen, atau nama aplikasi. Menulis angka ajaib (magic number) langsung di kode membuat program sulit dibaca dan rawan bug saat nilai tersebut harus diubah. C menyediakan beberapa mekanisme untuk mendefinisikan konstanta: makro #define, enum, dan const-qualified variable. Pada Chapter ini kita akan membandingkan ketiganya, melihat kapan masing-masing lebih tepat dipakai, serta memahami mengapa const int di C tidak sama dengan konstanta sejati.

Konstanta Simbolik dengan #define #

Makro #define diproses oleh preprocessor sebelum kompilasi. Setiap kali nama makro muncul di kode sumber, preprocessor menggantinya dengan teks definisi. Hasilnya: tidak ada variabel yang dialokasikan di memori, dan nilai konstanta bisa dipakai pada konteks yang membutuhkan constant expression seperti ukuran array statis.

c
#include <stdio.h>

/* Konstanta simbolik via #define */
#define PI 3.14159
#define NAMA_PRODUK "Belajar C"
#define MAX_LAGU 100

int main(void) {
    double r = 5.0;
    double luas = PI * r * r;

    printf("Nama  : %s\n", NAMA_PRODUK);
    printf("Jari-jari = %.2f, luas lingkaran = %.4f\n", r, luas);
    printf("Maks lagu dalam playlist = %d\n", MAX_LAGU);
    return 0;
}

Output yang Dihasilkan:

text
Nama  : Belajar C
Jari-jari = 5.00, luas lingkaran = 78.5397
Maks lagu dalam playlist = 100

Mari kita telaah baris-baris kode di atas:

  1. Baris 4 (#define PI 3.14159): preprocessor menggantikan setiap kemunculan PI di kode sumber dengan teks 3.14159. Tidak ada alokasi memori untuk PI.
  2. Baris 5 (#define NAMA_PRODUK "Belajar C"): string literal juga bisa dijadikan makro; setiap pemakaian NAMA_PRODUK akan diganti dengan string tersebut.
  3. Baris 6 (#define MAX_LAGU 100): konstanta integer yang juga bisa dipakai sebagai ukuran array.
  4. Baris 11 (PI * r * r): setelah preprocessor, ekspresi menjadi 3.14159 * r * r sebelum dikompilasi menjadi instruksi mesin.

enum untuk Konstanta Integer Bertipe Berurutan #

Kata kunci enum mendefinisikan tipe enumerasi yang berisi konstanta integer bertanda. Secara default, konstanta pertama bernilai 0 dan sisanya bertambah satu. enum lebih disarankan daripada #define untuk konstanta integer berurutan karena mendukung pemeriksaan tipe oleh debugger dan IDE.

c
#include <stdio.h>

/* Konstanta enumerasi */
enum Warna { MERAH, HIJAU, BIRU };

/* Konstanta objek (C: const-qualified variable, bukan konstanta sejati) */
const int BATAS_ATAS = 100;
const char *NAMA_APP = "Hugo Tutorial";

/* #define dipakai sebagai ukuran array */
#define UKURAN_BUF 8

int main(void) {
    enum Warna favorit = HIJAU;
    printf("Batas atas = %d\n", BATAS_ATAS);
    printf("Nama app   = %s\n", NAMA_APP);
    printf("Warna favorit (enum) = %d\n", favorit);

    /* #define bekerja sebagai ukuran array */
    int arr[UKURAN_BUF] = {1, 2, 3, 4, 5, 6, 7, 8};
    printf("Elemen terakhir arr = %d\n", arr[UKURAN_BUF - 1]);
    return 0;
}

Output yang Dihasilkan:

text
Batas atas = 100
Nama app   = Hugo Tutorial
Warna favorit (enum) = 1
Elemen terakhir arr = 8

Pada baris 4, enum Warna { MERAH, HIJAU, BIRU } mendefinisikan tipe baru enum Warna dengan tiga konstanta: MERAH = 0, HIJAU = 1, BIRU = 2. Pada baris 7, const int BATAS_ATAS = 100; sebenarnya mendeklarasikan variabel read-only, bukan konstanta sejati. Pada baris 8, const char *NAMA_APP adalah pointer yang menunjuk ke string literal—string literalnya sendiri read-only, tetapi pointer bisa diubah. Pada baris 19, arr[UKURAN_BUF] berhasil karena UKURAN_BUF adalah makro preprocessor yang diganti dengan 8 sebelum kompilasi.

Perbedaan const int dengan Konstanta Sejati #

Berbeda dengan C++, di C const int tidak dianggap constant expression. Akibatnya, kita tidak bisa memakai variabel const int sebagai ukuran array statis atau label case pada switch. Ini adalah perbedaan fundamental yang sering membingungkan programmer yang terbiasa dengan C++.

c
const int UKURAN = 10;
int arr[UKURAN];  /* ERROR di C, VALID di C++ */

Untuk membuat konstanta integer yang bisa dipakai sebagai ukuran array di C, gunakan #define atau enum:

c
#define UKURAN 10
int arr[UKURAN];   /* OK */

enum { UKURAN_ENUM = 10 };
int arr2[UKURAN_ENUM];  /* OK */

Function-Like Macro untuk Konstanta Berparameter #

Selain konstanta sederhana, #define juga bisa membentuk function-like macro yang menerima argumen. Macro jenis ini berguna untuk operasi sederhana yang ingin dihindari overhead pemanggilan fungsi, tetapi harus dipakai dengan hati-hati karena rentan bug prioritas operator.

c
#include <stdio.h>

#define KUADRAT(x) ((x) * (x))

int main(void) {
    int a = 5;
    printf("%d kuadrat = %d\n", a, KUADRAT(a));
    printf("4 kuadrat  = %d\n", KUADRAT(4));
    printf("3+1 kuadrat = %d\n", KUADRAT(3+1));
    return 0;
}

Output yang Dihasilkan:

text
5 kuadrat = 25
4 kuadrat  = 16
3+1 kuadrat = 16

Pada baris 3, makro KUADRAT(x) didefinisikan sebagai ((x) * (x)). Penggunaan tanda kurung di sekitar setiap x dan di sekitar seluruh ekspresi sangat penting. Tanpa tanda kurup luar, ekspresi KUADRAT(3+1) * 2 akan dievaluasi sebagai (3+1) * (3+1) * 2, bukan ((3+1) * (3+1)) * 2. Pada baris 9, ekspresi KUADRAT(3+1) diganti menjadi ((3+1) * (3+1)) yang menghasilkan 16. Jika tanda kurung dalam tidak ada, ekspresi akan menjadi 3+1 * 3+1 = 3 + 3 + 1 = 7 akibat prioritas perkalian lebih tinggi dari penjumlahan.

Memilih Mekanisme Konstanta #

Pemilihan mekanisme bergantung pada konteks:

  • #define: konstanta yang dipakai sebagai ukuran array, label case, atau nilai default lintas-file.
  • enum: konstanta integer berurutan yang mewakili kategori (warna, status, jenis error).
  • const: variabel read-only yang tipenya penting dan tidak dipakai sebagai constant expression. Cocok untuk pointer ke string atau nilai yang di-pass ke fungsi.
  • static const: konstanta dalam file yang tidak boleh di-link dari file lain.

Sebagai aturan praktis: gunakan enum jika memungkinkan karena paling aman dan mendukung type checking; gunakan #define jika konstanta harus dipakai pada konteks yang membutuhkan constant expression; gunakan const jika nilai harus memiliki tipe eksplisit dan tidak dipakai pada konteks constant expression.

Dengan tiga mekanisme ini, kita siap mempelajari qualifier const secara mendalam pada Chapter berikutnya.