#pragma once adalah alternatif modern terhadap pola include guard #ifndef/#define/#endif. Cukup satu baris di puncak header, dan compiler menjamin file tersebut hanya diproses sekali per translation unit, tanpa perlu memikirkan nama token guard. Directive ini didukung oleh GCC, Clang, MSVC, dan mayoritas compiler modern—meskipun secara teknis bukan bagian dari standar ISO C. Pada chapter ini kita akan membandingkan #pragma once dengan include guard klasik, melihat contoh praktis, dan membahas kapan masing-masing layak dipilih.
Cara Kerja #pragma once #
Mekanisme #pragma once berbeda dengan include guard. Pada include guard, preprocessor memutuskan inklusi berdasarkan token macro (MATH_UTILS_H sudah didefinisikan atau belum). Pada #pragma once, compiler menjaga daftar file (berdasarkan inode di sistem POSIX atau canonical path) yang sudah di-include; jika file yang sama diminta lagi, compiler langsung melewati seluruh file tanpa membacanya. Karena itu #pragma once bisa sedikit lebih cepat untuk header besar dan tidak rentan terhadap tabrakan nama token.
#pragma once
#define PI 3.14159265
int kuadrat(int x) {
return x * x;
}Header di atas menggunakan #pragma once di baris pertama. Tidak ada #ifndef, #define, atau #endif. Hal ini membuat header lebih bersih dan lebih mudah dibaca—terutama untuk file pendek.
Demonstrasi Multi-Inclusion #
Mari kita ulangi demonstrasi include guard dari chapter sebelumnya, tetapi kali ini memakai #pragma once.
File math_utils.h:
#pragma once
#define PI 3.14159265
int kuadrat(int x) {
return x * x;
}File util.h:
#pragma once
#include "math_utils.h"
double luas_lingkaran(double r) {
return PI * r * r;
}File main.c:
#include <stdio.h>
#include "math_utils.h"
#include "util.h"
#include "math_utils.h"
int main(void) {
printf("kuadrat(6) = %d\n", kuadrat(6));
printf("luas_lingkaran(3.0) = %.4f\n", luas_lingkaran(3.0));
return 0;
}Kompilasi dan jalankan:
gcc -std=c11 -Wall -Wextra -I. -o app main.c && ./appOutput yang Dihasilkan:
kuadrat(6) = 36
luas_lingkaran(3.0) = 28.2743Tiga kali inclusion math_utils.h (dua eksplisit di main.c, satu tidak langsung via util.h) sama sekali tidak menyebabkan error. Perilaku identik dengan include guard klasik, tetapi dengan jauh lebih sedikit baris kode di header.
Perbandingan dengan Include Guard Klasik #
Aspek-aspek berikut membedakan keduanya:
| Aspek | Include Guard #ifndef | #pragma once |
|---|---|---|
| Standar ISO C | Ya (sejak C89) | Tidak, tetapi didukung GCC/Clang/MSVC |
| Baris kode di header | 3 baris (ifndef/define/endif) | 1 baris |
| Risiko tabrakan token | Ada—token bisa tabrakan antar header | Tidak ada |
| Mekanisme deteksi | Token macro | Identitas file (inode/path) |
| Symlink / hard link | Tidak terpengaruh | Berpotensi keliru (file dianggap berbeda) |
| Portabilitas compiler lama | Sangat baik | Tergantung compiler |
Mari kita telaah implikasi masing-masing:
- Standar ISO C: include guard klasik dijamin ada di setiap compiler yang mematuhi standar C (sejak C89).
#pragma oncetidak standar, tetapi pada praktiknya didukung GCC, Clang, MSVC, Intel, dan IBM XL—yang mencakup hampir seluruh compiler yang akan kita pakai. - Risiko tabrakan token: pada proyek besar, dua header berbeda bisa tidak sengaja memilih token guard yang sama (mis.
UTILS_H). Akibatnya, salah satu header diam-diam dilewati.#pragma oncemenghilangkan risiko ini sepenuhnya. - Symlink dan hard link:
#pragma oncemengidentifikasi file via inode atau path canonical. Jika sebuah header diakses melalui dua path yang berbeda (mis. via symlink), compiler bisa menganggapnya dua file berbeda. Include guard klasik tidak terpengaruh karena hanya melihat token. - Kecepatan kompilasi: untuk header yang sangat besar (ribuan baris),
#pragma oncebisa lebih cepat karena compiler membuka file sekali dan langsung melewati pada inclusion berikutnya. Include guard tetap membuka file, lalu melewati setelah#ifndefpertama gagal.
Praktik dan Rekomendasi #
Banyak proyek open-source modern (LLVM, Chromium, Folly) memakai #pragma once sebagai standar. Namun, jika kita membangun pustaka yang harus tetap kompatibel dengan compiler lama atau embedded khusus, include guard klasik tetap menjadi pilihan paling aman. Beberapa proyek juga memakai keduanya—#pragma once di puncak dan include guard sebagai cadangan:
#pragma once
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
/* isi header */
#endif /* MATH_UTILS_H */Pola ini memberikan perlindungan ganda: jika compiler mendukung #pragma once, keduanya menjadi no-op; jika tidak, include guard klasik mengambil alih.