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:
#ifndef GEOMETRI_H
#define GEOMETRI_H
#define PI 3.14159
double luas_lingkaran(double jari);
double keliling_lingkaran(double jari);
#endifFile geometri.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:
#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:
Luas: 78.5397
Keliling: 31.4159Mari kita telaah baris-baris kode di atas:
#ifndef GEOMETRI_Hdan#define GEOMETRI_H(di geometri.h): mekanisme yang disebut include guard. Saat filegeometri.hdisisipkan untuk pertama kali, preprocessor mendefinisikan macroGEOMETRI_H. Jika file yang sama disisipkan lagi, preprocessor melihat macro sudah ada dan melewatkan isi file — mencegah deklarasi ganda.- Baris
double luas_lingkaran(double jari);di geometri.h: deklarasi fungsi — hanya tanda (signature) tanpa tubuh. Compiler yang membacamain.cjadi tahu nama fungsi, tipe parameter, dan tipe return. - Baris
double luas_lingkaran(double jari) { ... }di geometri.c: definisi fungsi — tubuh fungsi yang sesungguhnya dijalankan saat dipanggil. File ini juga meng-#includeheader-nya sendiri agar compiler memverifikasi kesesuaian deklarasi dengan definisi. #include "geometri.h"di main.c: menggunakan tanda kutip ganda untuk menyisipkan header buatan kita. Compiler mencari file di direktori yang sama dengan filemain.c.- Perintah
gcc main.c geometri.c -o program: compiler mengompilasi kedua file.cdan menautkannya menjadi satu executable. Linker kemudian mencocokkan pemanggilanluas_lingkarandimain.cdengan definisi digeometri.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:
| Header | Isi Utama |
|---|---|
stdio.h | Fungsi input/output seperti printf, scanf, fopen, fclose. |
stdlib.h | Utilitas umum seperti malloc, free, exit, atoi. |
math.h | Fungsi matematika seperti sqrt, pow, sin, cos. Memerlukan linker flag -lm pada GCC. |
string.h | Manipulasi string dan memori seperti strlen, strcpy, memcpy. |
stdbool.h | Tipe bool, true, false (sebelum C23 mengintegrasikannya langsung). |
Contoh penggunaan math.h:
#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:
akar(2.0) = 1.4142
pangkat(2.0, 3) = 8.0000Pada 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.
#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:
Elemen: 10, 20, 30Pada 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,
externvariabel); 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.