Pada program C yang lebih dari sekadar latihan kecil, kita biasanya memisahkan kode ke beberapa file supaya mudah dirawat. File *.c berisi implementasi (definisi fungsi), sedangkan file *.h (header file) berisi deklarasi — nama fungsi, tipe, dan macro yang ingin dipakai oleh file lain. Pemisahan inilah yang membuat banyak file .c dapat saling memanggil fungsi tanpa harus saling menyalin kode sumber. Pada Chapter ini kita akan mempelajari bagaimana header file bekerja, perbedaan deklarasi dengan definisi, serta konvensi penulisan header yang baik.

Deklarasi vs Definisi #

Deklarasi adalah pernyataan yang memberitahu compiler bahwa suatu nama (fungsi, variabel, tipe) ada dan memiliki tanda (signature) tertentu. Definisi adalah pernyataan yang benar-benar membuat entitas tersebut — mengalokasikan memori untuk variabel, atau menyediakan tubuh fungsi. Header file biasanya hanya berisi deklarasi, sedangkan file .c berisi definisi.

Perbedaan praktisnya dapat dilihat saat kita memecah program menjadi beberapa file. Buat tiga file berikut di direktori yang sama.

File geometri.h:

c
#ifndef GEOMETRI_H
#define GEOMETRI_H

#define PI 3.14159

double luas_lingkaran(double jari);
double keliling_lingkaran(double jari);

#endif

File geometri.c:

c
#include "geometri.h"

double luas_lingkaran(double jari) {
    return PI * jari * jari;
}

double keliling_lingkaran(double jari) {
    return 2.0 * PI * jari;
}

File main.c:

c
#include <stdio.h>
#include "geometri.h"

int main(void) {
    double r = 5.0;
    printf("Luas: %.4f\n", luas_lingkaran(r));
    printf("Keliling: %.4f\n", keliling_lingkaran(r));
    return 0;
}

Output yang Dihasilkan:

text
Luas: 78.5397
Keliling: 31.4159

Mari kita telaah baris-baris kode di atas:

  1. #ifndef GEOMETRI_H dan #define GEOMETRI_H (di geometri.h): mekanisme yang disebut include guard. Saat file geometri.h disisipkan untuk pertama kali, preprocessor mendefinisikan macro GEOMETRI_H. Jika file yang sama disisipkan lagi, preprocessor melihat macro sudah ada dan melewatkan isi file — mencegah deklarasi ganda.
  2. Baris double luas_lingkaran(double jari); di geometri.h: deklarasi fungsi — hanya tanda (signature) tanpa tubuh. Compiler yang membaca main.c jadi tahu nama fungsi, tipe parameter, dan tipe return.
  3. Baris double luas_lingkaran(double jari) { ... } di geometri.c: definisi fungsi — tubuh fungsi yang sesungguhnya dijalankan saat dipanggil. File ini juga meng-#include header-nya sendiri agar compiler memverifikasi kesesuaian deklarasi dengan definisi.
  4. #include "geometri.h" di main.c: menggunakan tanda kutip ganda untuk menyisipkan header buatan kita. Compiler mencari file di direktori yang sama dengan file main.c.
  5. Perintah gcc main.c geometri.c -o program: compiler mengompilasi kedua file .c dan menautkannya menjadi satu executable. Linker kemudian mencocokkan pemanggilan luas_lingkaran di main.c dengan definisi di geometri.c.

Header Pustaka Standar yang Sering Dipakai #

Pustaka standar C mengelompokkan fungsi-fungsi ke dalam beberapa header sesuai fungsinya. Berikut adalah tiga header yang paling sering kita pakai pada bab-bab awal:

HeaderIsi Utama
stdio.hFungsi input/output seperti printf, scanf, fopen, fclose.
stdlib.hUtilitas umum seperti malloc, free, exit, atoi.
math.hFungsi matematika seperti sqrt, pow, sin, cos. Memerlukan linker flag -lm pada GCC.
string.hManipulasi string dan memori seperti strlen, strcpy, memcpy.
stdbool.hTipe bool, true, false (sebelum C23 mengintegrasikannya langsung).

Contoh penggunaan math.h:

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

int main(void) {
    double x = 2.0;
    printf("akar(%.1f) = %.4f\n", x, sqrt(x));
    printf("pangkat(%.1f, 3) = %.4f\n", x, pow(x, 3));
    return 0;
}

Output yang Dihasilkan:

text
akar(2.0) = 1.4142
pangkat(2.0, 3) = 8.0000

Pada contoh di atas, header math.h berisi deklarasi fungsi sqrt dan pow. Saat menautkan program, GCC memerlukan flag -lm agar linker menemukan implementasi fungsi-fungsi tersebut di pustaka libm.

Header untuk Alokasi Memori #

Header stdlib.h menyediakan fungsi alokasi memori dinamis seperti malloc dan free. Kita akan mempelajari alokasi memori secara mendalam pada Section Pointer dan Memori; untuk saat ini, kita lihat dulu bagaimana header stdlib.h diperlukan agar deklarasi fungsi malloc dan free dikenali compiler.

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

int main(void) {
    int *arr = malloc(3 * sizeof(int));
    if (arr == NULL) {
        printf("Alokasi gagal\n");
        return 1;
    }
    arr[0] = 10;
    arr[1] = 20;
    arr[2] = 30;
    printf("Elemen: %d, %d, %d\n", arr[0], arr[1], arr[2]);
    free(arr);
    return 0;
}

Output yang Dihasilkan:

text
Elemen: 10, 20, 30

Pada contoh di atas, jika kita menghapus #include <stdlib.h>, compiler akan mengeluarkan warning karena compiler mengasumsikan malloc mengembalikan int — yang salah dan berbahaya pada sistem 64-bit karena ukuran int (4 byte) lebih kecil dari ukuran pointer (8 byte). Inilah salah satu alasan mengapa header file sangat penting: deklarasi yang benar membuat compiler memverifikasi tipe dengan tepat.

Ringkasan Konvensi Penulisan Header #

Beberapa konvensi yang banyak diikuti komunitas C:

  • Nama file header diakhiri .h; nama file sumber diakhiri .c.
  • Setiap header dilindungi include guard (#ifndef/#define/#endif) atau #pragma once.
  • Header hanya berisi deklarasi (fungsi, tipe, macro, extern variabel); definisi ditaruh di file .c.
  • Header pustaka standar dipakai dengan tanda kurung sudut (<stdio.h>); header lokal dipakai dengan tanda kutip ganda ("geometri.h").
  • Hindari header yang bergantung pada urutan penyertaan — semua header sebaiknya bisa berdiri sendiri tanpa memerlukan header lain disertakan lebih dulu oleh pemanggil.

Dengan konvensi ini, proyek C yang terdiri dari puluhan file .c dan .h tetap mudah dipahami karena setiap file memegang satu tugas yang jelas.