Memilih -std yang tepat adalah keputusan strategis dalam proyek C. Pilihan terlalu konservatif (mis. C89) membuat kode verbose dan ketinggalan fitur modern; pilihan terlalu agresif (mis. C23) bisa membuat kode tidak dapat dikompilasi di compiler lawas. Bab ini memetakan skenario penggunaan untuk setiap standar C—C89 untuk kode legacy, C99 untuk general-purpose, C11 untuk kode yang membutuhkan atomics dan threads, C17 untuk baseline stabil, dan C23 untuk fitur cutting edge. Kita juga akan melihat feature test macro __STDC_NO_ATOMICS, __STDC_NO_THREADS, dan __STDC_VERSION__ yang memungkinkan kode beradaptasi otomatis dengan compiler yang ada. Setelah membaca bab ini, kita akan tahu kapan harus memilih -std=c99 versus -std=c17 untuk proyek baru.
Lini Masa Flag -std GCC/Clang #
GCC dan Clang menerima beberapa nilai flag -std. Tabel berikut memetakan flag ke standar yang diaktifkan:
| Flag GCC/Clang | Standar Aktif | __STDC_VERSION__ | Catatan |
|---|---|---|---|
-std=c89 atau -std=c90 | C89/C90 | (undefined) | Mode paling konservatif |
-std=c99 atau -std=c9x | C99 | 199901L | General-purpose modern |
-std=c11 atau -std=c1x | C11 | 201112L | Atomics, threads, _Generic |
-std=c17 atau -std=c18 | C17 | 201710L | Bugfix C11, baseline stabil |
-std=c2x (GCC 14) / -std=c23 (GCC 15+) | C23 | 202000L (GCC 14) / 202311L (final) | Cutting edge |
-std=gnu89 / gnu99 dll. | Mode GNU | sama dengan ISO | Mengizinkan ekstensi GCC |
Sufiks gnu* (mis. gnu11) mengaktifkan ekstensi GCC seperti __attribute__, statement expression, dan computed goto. Default GCC adalah -std=gnu17 (atau gnu11 di GCC lama). Untuk kode yang harus portabel ke compiler lain, gunakan -std=cNN (tanpa gnu) dan aktifkan -pedantic untuk menangkap penggunaan ekstensi non-portabel.
Pemilihan Standar Berdasarkan Skenario #
Program berikut mendeteksi standar aktif dan menampilkan rekomendasi penggunaan. Kode sengaja ditulis dalam gaya C89-compatible (komentar /* */ saja, deklarasi di awal blok) agar dapat dikompilasi di semua standar—dari C89 hingga C23.
/* File: memilih_1.c - Deteksi standar aktif dan tampilkan rekomendasi */
#include <stdio.h>
int main(void) {
#if !defined(__STDC_VERSION__)
printf("Standar aktif : C89/C90 (atau K&R)\n");
printf("Rekomendasi : Pilih bila target compiler lawas (SDCC, vendor lama).\n");
printf("Tradeoff : Kode verbose, tidak ada // atau VLA.\n");
#elif __STDC_VERSION__ < 199901L
printf("Standar aktif : C95\n");
printf("Rekomendasi : Jarang dipilih; biasanya pakai C89 atau lompat ke C99.\n");
#elif __STDC_VERSION__ < 201112L
printf("Standar aktif : C99\n");
printf("Rekomendasi : General purpose, didukung compiler modern.\n");
#elif __STDC_VERSION__ < 201710L
printf("Standar aktif : C11\n");
printf("Rekomendasi : Atomics + threads, _Generic, _Static_assert.\n");
#elif __STDC_VERSION__ < 202000L
printf("Standar aktif : C17\n");
printf("Rekomendasi : Bugfix C11, baseline stabil untuk production.\n");
#else
printf("Standar aktif : C23\n");
printf("Rekomendasi : nullptr, constexpr, attributes - cutting edge.\n");
#endif
#ifdef __STDC_VERSION__
printf("__STDC_VERSION__ : %ldL\n", __STDC_VERSION__);
#endif
return 0;
}Compile dengan beberapa flag untuk melihat bagaimana output berubah:
gcc -std=c89 -Wall -Wextra -pedantic -o memilih_1_c89 memilih_1.c && ./memilih_1_c89
gcc -std=c99 -Wall -Wextra -pedantic -o memilih_1_c99 memilih_1.c && ./memilih_1_c99
gcc -std=c17 -Wall -Wextra -pedantic -o memilih_1_c17 memilih_1.c && ./memilih_1_c17
gcc -std=c2x -Wall -Wextra -pedantic -o memilih_1_c2x memilih_1.c && ./memilih_1_c2xOutput yang Dihasilkan (gcc -std=c89):
Standar aktif : C89/C90 (atau K&R)
Rekomendasi : Pilih bila target compiler lawas (SDCC, vendor lama).
Tradeoff : Kode verbose, tidak ada // atau VLA.Output yang Dihasilkan (gcc -std=c99):
Standar aktif : C99
Rekomendasi : General purpose, didukung compiler modern.
__STDC_VERSION__ : 199901LOutput yang Dihasilkan (gcc -std=c17):
Standar aktif : C17
Rekomendasi : Bugfix C11, baseline stabil untuk production.
__STDC_VERSION__ : 201710LOutput yang Dihasilkan (gcc -std=c2x, GCC 14):
Standar aktif : C23
Rekomendasi : nullptr, constexpr, attributes - cutting edge.
__STDC_VERSION__ : 202000LMari kita telaah baris-baris kode di atas:
- Baris 7 (
#if !defined(__STDC_VERSION__)): Jika__STDC_VERSION__tidak terdefinisi, compiler berjalan dalam mode C89/C90. Standar C89 tidak mendefinisikan macro__STDC_VERSION__; macro ini baru ada sejak C95. Karena itu kita cek dulu apakah terdefinisi sebelum membandingkan nilainya. - Baris 11 (
#elif __STDC_VERSION__ < 199901L): Nilai199409L(C95) lebih kecil dari199901L(C99), sehingga cabang ini cocok untuk C95. Pada praktiknya, hampir tidak ada proyek baru yang memilih C95 sebagai target eksplisit—biasanya kita pilih C89 atau langsung lompat ke C99. - Baris 14 (
#elif __STDC_VERSION__ < 201112L): Nilai199901L(C99) lebih kecil dari201112L(C11), sehingga cabang ini cocok untuk C99. C99 adalah pilihan “sweet spot” untuk kode portable yang tidak butuh atomics. - Baris 17-20 (
#elif __STDC_VERSION__ < 201710L): Cabang C11. Pilih bila kita membutuhkan_Generic,_Static_assert,_Atomic, atauthreads.h. - Baris 21-23 (
#elif __STDC_VERSION__ < 202000L): Cabang C17. Pilih untuk production stabil dengan dukungan compiler terluas. - Baris 24-26 (
#else ... C23): Cabang C23. Gunakannullptr,constexpr, dan attribute standar. Membutuhkan GCC 14+ atau Clang 18+.
Skenario Praktis: Feature Test Macro #
Ketika kita menulis library yang harus bekerja di banyak compiler (GCC, Clang, MSVC, vendor embedded), kita tidak bisa berasumsi semua fitur C11 tersedia. C11 menambahkan macro feature test __STDC_NO_ATOMICS dan __STDC_NO_THREADS: jika compiler mendefinisikan macro ini, berarti fitur tersebut tidak didukung. Program berikut memeriksa ketersediaan fitur sebelum menggunakannya:
// File: memilih_2.c - Skenario: build configuration dengan feature test macro
#include <stdio.h>
#include <stdint.h>
// Konfigurasi: pilih standar minimum yang dibutuhkan
#define NEEDS_ATOMICS 1
#define NEEDS_THREADS 1
#define NEEDS_NULLPTR 1
int main(void) {
#if NEEDS_ATOMICS && !defined(__STDC_NO_ATOMICS__)
printf("Atomics : didukung\n");
#else
printf("Atomics : TIDAK didukung - perlu C11+\n");
#endif
#if NEEDS_THREADS && !defined(__STDC_NO_THREADS__)
printf("threads.h: didukung\n");
#else
printf("threads.h: TIDAK didukung - gunakan pthread atau stdatomic\n");
#endif
#if NEEDS_NULLPTR
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
printf("nullptr : didukung (C23+)\n");
#else
printf("nullptr : tidak tersedia - gunakan NULL atau 0\n");
#endif
#endif
printf("sizeof(int) : %zu byte\n", sizeof(int));
printf("sizeof(void*): %zu byte\n", sizeof(void*));
return 0;
}Compile dan jalankan:
gcc -std=c17 -Wall -Wextra -pedantic -o memilih_2 memilih_2.c
./memilih_2Output yang Dihasilkan (gcc -std=c17):
Atomics : didukung
threads.h: didukung
nullptr : tidak tersedia - gunakan NULL atau 0
sizeof(int) : 4 byte
sizeof(void*): 8 bytePola di atas adalah strategi yang umum dipakai library lintas compiler: tetapkan macro NEEDS_* di header konfigurasi proyek, lalu cek apakah compiler mendukung fitur tersebut via __STDC_NO_* atau __STDC_VERSION__. Jika tidak didukung, fallback ke implementasi alternatif (mis. pthread untuk threads, atau macro NULL untuk nullptr).
Panduan Memilih Standar untuk Proyek Baru #
Berikut rekomendasi praktis berdasarkan skenario:
| Skenario | Standar Disarankan | Alasan |
|---|---|---|
| Firmware mikrokontroler 8-bit/16-bit (SDCC, Keil C51) | -std=c89 -pedantic | Compiler embedded tua sering hanya patuh C89 |
| Library open-source publik (mis. parser JSON, ring buffer) | -std=c99 -pedantic | Didukung semua compiler modern, sintaks ringkas |
| Aplikasi server modern (Linux/macOS) | -std=c17 -pedantic | Baseline stabil, atomics dan threads tersedia |
| Library yang harus portabel ke MSVC | -std=c17 (atau -std=c11) | MSVC mendukung C17 sejak 2019 16.8 |
| Proyek greenfield dengan GCC/Clang terbaru | -std=c2x -pedantic (C23) | nullptr, constexpr, attribute standar |
| Kernel mode / freestanding environment | -std=c17 -ffreestanding | Tanpa hosted library, atomics tetap berfungsi |