C bukan bahasa yang dipakai untuk menulis aplikasi web dashboard atau skrip analisis data sekali jalan. C dipakai pada lapisan yang membutuhkan kinerja tinggi, kontrol langsung terhadap perangkat keras, dan ketergantungan minimum pada runtime lain. Pada Chapter ini kita akan melihat bidang-bidang utama yang memanfaatkan C, sekaligus mencoba beberapa API standar yang menjadi pintu masuk C ke sistem operasi. Dengan memahami konteks pemakaian C, kita akan tahu kapan harus memilih C dan kapan sebaiknya memilih bahasa lain.

Bidang Pemakaian Utama C #

C hadir di banyak lapisan fundamental perangkat lunak modern. Beberapa bidang yang sangat bergantung pada C antara lain:

  • Sistem operasi: kernel Linux, kernel FreeBSD, dan sebagian besar kernel Windows ditulis dalam C.
  • Sistem tertanam (embedded): firmware mikrokontroler, driver perangkat, dan kode real-time di perangkat IoT.
  • Database engine: SQLite, PostgreSQL, MySQL, dan Redis semuanya ditulis dalam C.
  • Interpreter dan runtime bahasa lain: CPython (Python), PHP Zend Engine, Lua, dan Ruby MRI semuanya diimplementasikan dalam C.
  • Library sistem: glibc, musl, OpenSSL, zlib, dan libcurl menjadi fondasi yang dipakai bahasa lain.
  • Game engine: banyak komponen kinerja-kritis di Unreal Engine dan Unity ditulis dalam C atau C++.
  • Compiler dan tools: GCC, Clang, Make, dan CMake semuanya berbasis C/C++.

Cocoknya C untuk bidang-bidang tersebut berasal dari tiga sifat utama: kompilasi ke kode mesin asli yang cepat, akses langsung ke system call lewat header POSIX dan Windows API, serta kontrol penuh terhadap alokasi memori.

Mengakses Informasi Sistem Operasi #

Salah satu kekuatan C adalah kemudahan mengakses informasi sistem operasi lewat API standar. Pada sistem POSIX (Linux, macOS, BSD), header <sys/utsname.h> menyediakan fungsi uname yang mengembalikan nama sistem, versi kernel, dan arsitektur mesin. Berikut contoh kode yang memakai API tersebut:

c
#include <stdio.h>
#include <sys/utsname.h>

int main(void) {
    struct utsname info;
    if (uname(&info) == 0) {
        printf("Sistem operasi : %s\n", info.sysname);
        printf("Hostname       : %s\n", info.nodename);
        printf("Versi kernel   : %s\n", info.release);
        printf("Arsitektur     : %s\n", info.machine);
    } else {
        printf("Gagal mengambil info sistem.\n");
    }
    return 0;
}

Output yang Dihasilkan:

text
Sistem operasi : Linux
Hostname       : c-6acd9659-14810412-33ddf6d3a64e
Versi kernel   : 5.10.134-013.15.kangaroo.al8.x86_64
Arsitektur     : x86_64

Mari kita telaah baris-baris kode di atas:

  1. Baris 2 (#include <sys/utsname.h>): header POSIX yang mendefinisikan tipe struct utsname dan fungsi uname.
  2. Baris 5 (struct utsname info;): mendeklarasikan variabel info bertipe struct utsname yang akan menampung hasil panggilan uname.
  3. Baris 6 (uname(&info) == 0): memanggil fungsi uname dengan alamat info; fungsi mengembalikan 0 bila sukses.
  4. Baris 7-10 (printf(...)): mencetak field-field struktur seperti info.sysname dan info.machine.
  5. Baris 12 (else): bila uname gagal (misalnya dipanggil di lingkungan non-POSIX), program mencetak pesan kesalahan.

Membaca Environment Variable #

Banyak program C membaca konfigurasi dari environment variable yang diatur shell sebelum program dijalankan. Standar C menyediakan fungsi getenv di header <stdlib.h> untuk mengambil nilai berdasarkan nama. Fungsi ini mengembalikan pointer ke string, atau NULL bila variabel tidak ditemukan.

c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *user = getenv("USER");
    const char *shell = getenv("SHELL");
    const char *home = getenv("HOME");
    printf("USER  = %s\n", user  ? user  : "(kosong)");
    printf("SHELL = %s\n", shell ? shell : "(kosong)");
    printf("HOME  = %s\n", home  ? home  : "(kosong)");
    return 0;
}

Output yang Dihasilkan:

text
USER  = z
SHELL = /bin/bash
HOME  = /home/z

Mari kita telaah baris-baris kode di atas:

  1. Baris 2 (#include <stdlib.h>): menyertakan header standar yang mendeklarasikan fungsi getenv.
  2. Baris 5 (const char *user = getenv("USER");): pointer user diisi dengan alamat string nilai variabel USER, atau NULL bila variabel tidak ada.
  3. Baris 8 (user ? user : "(kosong)"): operator ternary memilih user bila tidak NULL, jika tidak dipilih string literal "(kosong)".
  4. Baris 9-10: pola yang sama dipakai untuk variabel SHELL dan HOME.

Ekosistem dan Komunitas #

Komunitas C tersebar di banyak proyek open source besar. Berikut daftar proyek populer yang kode sumbernya bisa kita pelajari langsung:

c
#include <stdio.h>
#include <string.h>

int main(void) {
    const char *proyek[] = {
        "Kernel Linux",
        "Git",
        "SQLite",
        "curl",
        "Redis",
        "Nginx"
    };
    size_t n = sizeof(proyek) / sizeof(proyek[0]);
    printf("Daftar proyek open source berbasis C:\n");
    for (size_t i = 0; i < n; i++) {
        printf("  %zu. %s (%zu byte)\n", i + 1, proyek[i], strlen(proyek[i]));
    }
    return 0;
}

Output yang Dihasilkan:

text
Daftar proyek open source berbasis C:
  1. Kernel Linux (12 byte)
  2. Git (3 byte)
  3. SQLite (6 byte)
  4. curl (4 byte)
  5. Redis (5 byte)
  6. Nginx (5 byte)

Mari kita telaah baris-baris kode di atas:

  1. Baris 5-12 (const char *proyek[] = {...};): array berisi enam pointer ke string literal.
  2. Baris 13 (sizeof(proyek) / sizeof(proyek[0])): idiom standar C untuk menghitung jumlah elemen array secara statis pada saat kompilasi.
  3. Baris 15 (for (size_t i = 0; i < n; i++)): loop memakai tipe size_t untuk indeks karena membandingkan dengan n yang bertipe size_t.
  4. Baris 16 (strlen(proyek[i])): menghitung panjang string tanpa termasuk karakter terminator nol.
  5. Baris 16 (%zu): format specifier yang benar untuk mencetak size_t.