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/ClangStandar Aktif__STDC_VERSION__Catatan
-std=c89 atau -std=c90C89/C90(undefined)Mode paling konservatif
-std=c99 atau -std=c9xC99199901LGeneral-purpose modern
-std=c11 atau -std=c1xC11201112LAtomics, threads, _Generic
-std=c17 atau -std=c18C17201710LBugfix C11, baseline stabil
-std=c2x (GCC 14) / -std=c23 (GCC 15+)C23202000L (GCC 14) / 202311L (final)Cutting edge
-std=gnu89 / gnu99 dll.Mode GNUsama dengan ISOMengizinkan 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.

c
/* 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:

bash
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_c2x

Output yang Dihasilkan (gcc -std=c89):

text
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):

text
Standar aktif : C99
Rekomendasi    : General purpose, didukung compiler modern.
__STDC_VERSION__ : 199901L

Output yang Dihasilkan (gcc -std=c17):

text
Standar aktif : C17
Rekomendasi    : Bugfix C11, baseline stabil untuk production.
__STDC_VERSION__ : 201710L

Output yang Dihasilkan (gcc -std=c2x, GCC 14):

text
Standar aktif : C23
Rekomendasi    : nullptr, constexpr, attributes - cutting edge.
__STDC_VERSION__ : 202000L

Mari kita telaah baris-baris kode di atas:

  1. 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.
  2. Baris 11 (#elif __STDC_VERSION__ < 199901L): Nilai 199409L (C95) lebih kecil dari 199901L (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.
  3. Baris 14 (#elif __STDC_VERSION__ < 201112L): Nilai 199901L (C99) lebih kecil dari 201112L (C11), sehingga cabang ini cocok untuk C99. C99 adalah pilihan “sweet spot” untuk kode portable yang tidak butuh atomics.
  4. Baris 17-20 (#elif __STDC_VERSION__ < 201710L): Cabang C11. Pilih bila kita membutuhkan _Generic, _Static_assert, _Atomic, atau threads.h.
  5. Baris 21-23 (#elif __STDC_VERSION__ < 202000L): Cabang C17. Pilih untuk production stabil dengan dukungan compiler terluas.
  6. Baris 24-26 (#else ... C23): Cabang C23. Gunakan nullptr, 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:

c
// 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:

bash
gcc -std=c17 -Wall -Wextra -pedantic -o memilih_2 memilih_2.c
./memilih_2

Output yang Dihasilkan (gcc -std=c17):

text
Atomics  : didukung
threads.h: didukung
nullptr  : tidak tersedia - gunakan NULL atau 0
sizeof(int)  : 4 byte
sizeof(void*): 8 byte

Pola 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:

SkenarioStandar DisarankanAlasan
Firmware mikrokontroler 8-bit/16-bit (SDCC, Keil C51)-std=c89 -pedanticCompiler embedded tua sering hanya patuh C89
Library open-source publik (mis. parser JSON, ring buffer)-std=c99 -pedanticDidukung semua compiler modern, sintaks ringkas
Aplikasi server modern (Linux/macOS)-std=c17 -pedanticBaseline 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 -ffreestandingTanpa hosted library, atomics tetap berfungsi