Ketika sebuah proyek C tumbuh dari satu file menjadi puluhan modul, kunci yang membedakan kode yang mudah dibaca dari kode yang sulit dipelihara bukanlah fitur bahasa yang dipakai, melainkan konsistensi penamaan. Linux kernel, GNU C library, dan proyek open-source besar lainnya sama-sama memakai C, tetapi masing-masing memiliki aturan penamaan sendiri yang diterapkan secara ketat. Bab ini membuka section Coding Standards dan Architecture dengan membahas tiga gaya penamaan utama di C—snake_case, CamelCase, dan ALL_CAPS—serta pola PREFIX_ untuk menyegregasi simbol antar modul. Kita juga akan melihat mengapa nama-nama deskriptif lebih bernilai daripada komentar, dan bagaimana penamaan yang buruk langsung membuka peluang bug.

Tiga Gaya Penamaan Utama di C #

C adalah bahasa yang sangat bebas dalam hal identifier. Compiler tidak peduli apakah kita menamai variabel totalHarga, total_harga, atau TOTALHARGA. Komunitas C, bagaimapun, telah menyepakati sejumlah konvensi yang membuat kode terbaca konsisten lintas proyek.

GayaUntukContoh
snake_caseVariabel, fungsi, field structjumlah_pegawai, hitung_rata_rata
CamelCase atau lowerCamelCaseJarang di C; lebih umum di C++/JavahitungRataRata
ALL_CAPS dengan underscoreKonstanta compile-time dan macroMAX_BUFFER_SIZE, PI
PREFIX_namaSimbol publik modulvector_push, pegawai_buat
nama_tSuffix untuk typedefvector_t, pegawai_t

Komunitas C (termasuk Linux kernel dan GNU Coding Standards) menetapkan snake_case untuk variabel dan fungsi, ALL_CAPS untuk macro, dan suffix _t untuk tipe. CamelCase umumnya dihindari di C karena dapat menyamarkan apakah sebuah identifier adalah tipe atau variabel—banyak compiler C membaca HitungTotal sebagai nama fungsi biasa, bukan tipe.

Konstanta dan Macro Pakai ALL_CAPS #

Aturan paling universal di C adalah: macro dan konstanta compile-time ditulis dalam ALL_CAPS. Alasannya bukan estetika—kapital memberi sinyal visual ke pembaca bahwa identifier tersebut bukan variabel biasa yang bisa diubah saat runtime, melainkan substitusi preprocessor yang mungkin memiliki efek samping tak terduga.

c
/* File: naming1.c - Demonstrasikan konvensi penamaan C */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Konstanta compile-time: ALL_CAPS */
#define MAX_PEGAWAI   100
#define NAMA_MAX_LEN  64

/* Macro pembantu: ALL_CAPS dengan PREFIX */
#define ARR_LEN(arr)  (sizeof(arr) / sizeof((arr)[0]))

/* Tipe publik modul: PREFIX_nama_t */
typedef struct {
    char nama[NAMA_MAX_LEN];
    int  umur;
} pegawai_t;

/* Fungsi modul dengan PREFIX_ */
static int pegawai_buat(pegawai_t *p, const char *nama, int umur)
{
    if (p == NULL || nama == NULL) {
        return -1;                       /* error code */
    }
    if (strlen(nama) >= NAMA_MAX_LEN) {
        return -2;                      /* nama terlalu panjang */
    }
    strcpy(p->nama, nama);
    p->umur = umur;
    return 0;                           /* sukses */
}

/* Variabel lokal: snake_case */
int main(void)
{
    pegawai_t daftar[MAX_PEGAWAI];
    int jumlah_pegawai = 0;
    int rc;

    rc = pegawai_buat(&daftar[jumlah_pegawai], "Budi", 32);
    if (rc == 0) {
        jumlah_pegawai++;
    }
    rc = pegawai_buat(&daftar[jumlah_pegawai], "Siti", 28);
    if (rc == 0) {
        jumlah_pegawai++;
    }

    printf("Jumlah pegawai terdaftar: %d/%d\n", jumlah_pegawai, (int)ARR_LEN(daftar));
    for (int i = 0; i < jumlah_pegawai; i++) {
        printf("  [%d] %-10s umur %d\n", i, daftar[i].nama, daftar[i].umur);
    }
    return 0;
}

Output yang Dihasilkan:

text
Jumlah pegawai terdaftar: 2/100
  [0] Budi       umur 32
  [1] Siti       umur 28

Mari kita telaah baris-baris kode di atas:

  1. Baris 7-8 (#define MAX_PEGAWAI 100): Konstanta ukuran array ditulis dalam ALL_CAPS. Pembaca yang melihat MAX_PEGAWAI langsung tahu identifier ini adalah konstanta compile-time, bukan variabel yang bisa diubah saat runtime.
  2. Baris 11 (#define ARR_LEN(arr)): Macro pembantu juga ALL_CAPS. Macro bisa mengandung efek samping jika argumen dipakai berulang; kapital memberi peringatan visual “ini bukan fungsi biasa”.
  3. Baris 14-17 (typedef struct { ... } pegawai_t): Tipe publik diberi suffix _t. Pembaca yang menulis pegawai_t p; langsung tahu p adalah instance dari struct, bukan tipe primitif.
  4. Baris 20 (static int pegawai_buat(pegawai_t *p, ...)): Fungsi publik modul pegawai diberi prefix pegawai_ agar tidak bertabrakan dengan fungsi lain di program besar. Kata kerja buat menandakan fungsi tersebut membuat objek baru.
  5. Baris 35 (int jumlah_pegawai = 0;): Variabel lokal memakai snake_case deskriptif. Nama jumlah_pegawai langsung menjelaskan isi variabel; tidak perlu komentar tambahan.

PREFIX_ untuk Simbol Publik Modul #

Saat sebuah modul C dipakai bersama oleh banyak file, setiap simbol publik (fungsi non-static, global variabel, tipe) berisiko bertabrakan dengan simbol lain yang bernama sama. Linker C menggunakan flat namespace untuk simbol global—tidak ada import atau namespace seperti di Python atau Rust. Solusinya adalah memberi prefix pada setiap simbol publik dengan nama modul.

c
/* File: naming2.c - PREFIX_ untuk menghindari bentrokan simbol */
#include <stdio.h>
#include <stdlib.h>

/* Modul "vector" sederhana dengan prefix vector_ */
typedef struct {
    int  *data;
    size_t len;
    size_t cap;
} vector_t;

static int vector_push(vector_t *v, int value)
{
    if (v->len >= v->cap) {
        size_t new_cap = (v->cap == 0) ? 4 : v->cap * 2;
        int *p = realloc(v->data, new_cap * sizeof(int));
        if (p == NULL) return -1;
        v->data = p;
        v->cap  = new_cap;
    }
    v->data[v->len++] = value;
    return 0;
}

static void vector_free(vector_t *v)
{
    free(v->data);
    v->data = NULL;
    v->len = v->cap = 0;
}

int main(void)
{
    vector_t v = {0};
    for (int i = 1; i <= 5; i++) {
        if (vector_push(&v, i * 10) != 0) {
            fprintf(stderr, "vector_push gagal\n");
            vector_free(&v);
            return 1;
        }
    }
    printf("vector_t len=%zu cap=%zu:", v.len, v.cap);
    for (size_t i = 0; i < v.len; i++) {
        printf(" %d", v.data[i]);
    }
    printf("\n");
    vector_free(&v);
    return 0;
}

Output yang Dihasilkan:

text
vector_t len=5 cap=8: 10 20 30 40 50

Pada kode di atas, semua simbol publik modul diawali vector_: vector_push, vector_free, vector_t. Jika kelak kita menambah modul lain bernama list_ dengan fungsi list_push, kedua modul dapat dikompilasi bersama tanpa konflik. Inilah pola yang dipakai oleh library besar seperti GLib (g_list_append, g_hash_table_new) dan cURL (curl_easy_init, curl_easy_setopt).

Nama Deskriptif Menggantikan Komentar #

Penamaan yang baik adalah bentuk dokumentasi termurah—biaya nol, hidup selama kode hidup, dan selalu sinkron dengan implementasi. Sebaliknya, komentar bisa menjadi usang ketika kode berubah tetapi komentar tidak diperbarui. Berikut perbandingan langsung antara nama tidak deskriptif versus nama yang menjelaskan dirinya sendiri:

c
/* File: naming3.c - Demo penamaan buruk vs baik */
#include <stdio.h>

/* Versi BURUK: nama tidak deskriptif */
static int f(int a, int b)
{
    int x = a + b;
    int y = a - b;
    return x * y;
}

/* Versi BAIK: nama jelas dan terngkap maksudnya */
static int hitung_selisih_kuadrat(int nilai_a, int nilai_b)
{
    int jumlah = nilai_a + nilai_b;
    int selisih = nilai_a - nilai_b;
    return jumlah * selisih;
}

int main(void)
{
    int p = 7, q = 3;
    printf("f(%d, %d) = %d\n", p, q, f(p, q));
    printf("hitung_selisih_kuadrat(%d, %d) = %d\n",
           p, q, hitung_selisih_kuadrat(p, q));
    return 0;
}

Output yang Dihasilkan:

text
f(7, 3) = 40
hitung_selisih_kuadrat(7, 3) = 40

Kedua fungsi menghasilkan output identik, tetapi versi hitung_selisih_kuadrat langsung menjelaskan bahwa jumlah * selisih adalah identitas aljabar (a+b)(a-b) = a²-b². Pembaca yang melihat f(a, b) pasti akan kesulitan menebak maksudnya tanpa membaca isi fungsi—justru menambah beban kognitif tanpa alasan.

Aturan Praktis Konsistensi Penamaan #

Berikut ringkasan aturan yang biasanya kami terapkan di proyek C:

  • Pilih satu gaya lalu patuhi di seluruh proyek. Jangan campur snake_case dan CamelCase di file yang sama.
  • Gunakan snake_case untuk variabel dan fungsi. Inilah konvensi Linux kernel, GNU, dan sebagian besar library C.
  • ALL_CAPS hanya untuk macro dan konstanta preprocessor. Hindari memakainya untuk variabel static const—static const int max_pegawai = 100; lebih sesuai karena variabel ini punya alamat di memori, bukan sekadar substitusi teks.
  • Beri prefix pada simbol publik modul. Mis. vector_push, parser_next_token, config_get_int.
  • Suffix _t untuk typedef, atau hindari typedef sama sekali seperti Linux kernel yang menulis struct nama langsung tanpa typedef.
  • Nama boolean harus bisa dibaca sebagai pertanyaan. is_admin, has_permission, should_retry jelas lebih informatif daripada flag, status, temp.
  • Singkatan umum boleh dipakai jika konteks jelas. buf untuk buffer, fd untuk file descriptor, ptr untuk pointer, cnt untuk counter. Hindari singkatan yang tidak umum seperti c untuk count di fungsi yang juga memiliki parameter lain bernama c (char).