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.
| Gaya | Untuk | Contoh |
|---|---|---|
snake_case | Variabel, fungsi, field struct | jumlah_pegawai, hitung_rata_rata |
CamelCase atau lowerCamelCase | Jarang di C; lebih umum di C++/Java | hitungRataRata |
ALL_CAPS dengan underscore | Konstanta compile-time dan macro | MAX_BUFFER_SIZE, PI |
PREFIX_nama | Simbol publik modul | vector_push, pegawai_buat |
nama_t | Suffix untuk typedef | vector_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.
/* 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:
Jumlah pegawai terdaftar: 2/100
[0] Budi umur 32
[1] Siti umur 28Mari kita telaah baris-baris kode di atas:
- Baris 7-8 (
#define MAX_PEGAWAI 100): Konstanta ukuran array ditulis dalam ALL_CAPS. Pembaca yang melihatMAX_PEGAWAIlangsung tahu identifier ini adalah konstanta compile-time, bukan variabel yang bisa diubah saat runtime. - 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”. - Baris 14-17 (
typedef struct { ... } pegawai_t): Tipe publik diberi suffix_t. Pembaca yang menulispegawai_t p;langsung tahupadalah instance dari struct, bukan tipe primitif. - Baris 20 (
static int pegawai_buat(pegawai_t *p, ...)): Fungsi publik modulpegawaidiberi prefixpegawai_agar tidak bertabrakan dengan fungsi lain di program besar. Kata kerjabuatmenandakan fungsi tersebut membuat objek baru. - Baris 35 (
int jumlah_pegawai = 0;): Variabel lokal memakai snake_case deskriptif. Namajumlah_pegawailangsung 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.
/* 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:
vector_t len=5 cap=8: 10 20 30 40 50Pada 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:
/* 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:
f(7, 3) = 40
hitung_selisih_kuadrat(7, 3) = 40Kedua 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_casedanCamelCasedi file yang sama. - Gunakan
snake_caseuntuk variabel dan fungsi. Inilah konvensi Linux kernel, GNU, dan sebagian besar library C. ALL_CAPShanya untuk macro dan konstanta preprocessor. Hindari memakainya untuk variabelstatic 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
_tuntuk typedef, atau hindari typedef sama sekali seperti Linux kernel yang menulisstruct namalangsung tanpa typedef. - Nama boolean harus bisa dibaca sebagai pertanyaan.
is_admin,has_permission,should_retryjelas lebih informatif daripadaflag,status,temp. - Singkatan umum boleh dipakai jika konteks jelas.
bufuntuk buffer,fduntuk file descriptor,ptruntuk pointer,cntuntuk counter. Hindari singkatan yang tidak umum seperticuntukcountdi fungsi yang juga memiliki parameter lain bernamac(char).