C23 (ISO/IEC 9899:2024) adalah lompatan fitur terbesar sejak C11. Standar ini mengadopsi banyak ide modern dari C++ dan praktik industri: nullptr sebagai pengganti NULL, true/false sebagai keyword (bukan lagi macro dari stdbool.h), constexpr untuk konstanta compile-time yang benar-benar typed, attribute [[nodiscard]]/[[deprecated]]/[[maybe_unused]] standar, typeof dan auto sebagai keyword resmi, serta #embed untuk memasukkan file binary langsung ke kode. Bab ini menunjukkan fitur-fitur utama dengan kode yang di-compile menggunakan gcc -std=c2x -pedantic. Kita juga akan melihat bagaimana C23 menghapus kebiasaan lama yang ambigu (mis. NULL yang bisa berarti 0 integer atau pointer null) dan menggantinya dengan konstruk yang lebih aman.
nullptr, true/false Keyword, dan constexpr #
Tiga perubahan paling terasa di C23 adalah: nullptr sebagai konstanta null pointer bertipe nullptr_t, true/false dipromosikan dari macro di stdbool.h menjadi keyword bahasa, dan constexpr untuk mendefinisikan konstanta compile-time yang benar-benar bertipe (bukan macro text substitution).
// File: c23_1.c - true/false sebagai keyword, nullptr, constexpr
#include <stdio.h>
#include <stdbool.h> // masih bisa diinclude, true/false sekarang keyword
// constexpr: konstanta compile-time yang benar-benar typed
constexpr int MAX_BUF = 64;
constexpr double PI = 3.14159265358979;
// nullptr: pengganti NULL dan 0 sebagai pointer null
static int *cari(int *arr, int n, int target) {
for (int i = 0; i < n; ++i) {
if (arr[i] == target) {
return &arr[i];
}
}
return nullptr; // nullptr bertipe nullptr_t, bukan int
}
int main(void) {
// true/false sekarang keyword, tidak perlu #include <stdbool.h>
bool lulus = true;
if (lulus) {
printf("Status: lulus\n");
}
int data[] = {10, 20, 30, 40, 50};
int *p = cari(data, 5, 30);
if (p != nullptr) {
printf("Ditemukan di indeks %ld, nilai %d\n", p - data, *p);
} else {
printf("Tidak ditemukan\n");
}
// nullptr_t bisa di-compare dengan pointer apapun
int *q = nullptr;
if (q == nullptr) {
printf("q adalah null pointer\n");
}
printf("MAX_BUF = %d\n", MAX_BUF);
printf("PI = %.14f\n", PI);
return 0;
}Compile dan jalankan dengan flag -std=c2x (GCC 14 masih memakai nama c2x; GCC 15+ akan menggunakan c23):
gcc -std=c2x -Wall -Wextra -pedantic -o c23_1 c23_1.c
./c23_1Output yang Dihasilkan:
Status: lulus
Ditemukan di indeks 2, nilai 30
q adalah null pointer
MAX_BUF = 64
PI = 3.14159265358979Mari kita telaah baris-baris kode di atas:
- Baris 7-8 (
constexpr int MAX_BUF = 64; constexpr double PI = ...;):constexprmemberi tahu compiler bahwa variabel ini adalah konstanta compile-time yang dapat dipakai dalam konteks yang mensyaratkan konstanta (mis. ukuran array static, labelcase, initializer global). Berbeda denganconst,constexprmenjamin nilai benar-benar dievaluasi saat kompilasi, bukan saat runtime. - Baris 11-18 (
static int *cari(...) { ... return nullptr; }): Fungsi mengembalikanint *. Jika target tidak ditemukan, kita kembalikannullptralih-alihNULLatau0. Tipenullptradalahnullptr_tyang implisit convertible ke pointer apa pun, tetapi tidak convertible keint—ini mencegah bug klasikif (cari(...) == 0)yang ambigu antara “integer 0” dan “null pointer”. - Baris 21-23 (
bool lulus = true;): Tipebooldengan nilaitrue/falseadalah keyword resmi di C23. Sebelum C23, kita harus#include <stdbool.h>yang mendefinisikanbool,true,falsesebagai macro. Di C23, header tersebut boleh di-include atau tidak—keyword tetap tersedia. - Baris 27-32 (
if (p != nullptr) ...): Pembandingan pointer dengannullptrlebih eksplisit daripadaif (p)atauif (p != NULL). Compiler tahu persis bahwapdibandingkan dengan null pointer, bukan dengan integer 0. - Baris 35-37 (
int *q = nullptr; if (q == nullptr)): Variabelqdiinisialisasi dengannullptrbertipenullptr_t. Konversi implisit darinullptr_tkeint *didefinisikan oleh standar C23.
Attribute Standar: [[nodiscard]], [[deprecated]], [[maybe_unused]] #
C23 memfinalisasi sintaks attribute [[...]] yang diperkenalkan di C23 (sebelum C11, GCC memakai __attribute__((...)) sebagai ekstensi). Attribute standar utama adalah [[nodiscard]] (warning jika return value dibuang), [[deprecated]] (warning jika fungsi dipanggil), dan [[maybe_unused]] (menekan warning unused).
// File: c23_2.c - Attributes [[nodiscard]], [[deprecated]], [[maybe_unused]]
#include <stdio.h>
// [[nodiscard]]: warning jika pemanggil membuang return value
[[nodiscard]] int hitung_total(int *arr, int n) {
int total = 0;
for (int i = 0; i < n; ++i) total += arr[i];
return total;
}
// [[deprecated]]: warning jika fungsi dipanggil
[[deprecated("gunakan versi_v2() sebagai gantinya")]]
int versi_lama(void) {
return 42;
}
// [[maybe_unused]]: menekan warning -Wunused
[[maybe_unused]] static int helper_tidak_dipakai(void) {
return 99;
}
int main(void) {
int data[] = {1, 2, 3, 4, 5};
// Pembuang return value memicu warning karena [[nodiscard]]
int t = hitung_total(data, 5);
printf("Total: %d\n", t);
return 0;
}Compile dan jalankan:
gcc -std=c2x -Wall -Wextra -pedantic -o c23_2 c23_2.c
./c23_2Output yang Dihasilkan:
Total: 15Untuk melihat warning yang dipicu [[nodiscard]], modifikasi main agar membuang return value:
// File: c23_2b.c - Demo warning [[nodiscard]]
#include <stdio.h>
[[nodiscard]] int hitung_total(int *arr, int n) {
int total = 0;
for (int i = 0; i < n; ++i) total += arr[i];
return total;
}
int main(void) {
int data[] = {1, 2, 3};
hitung_total(data, 3); // hasil dibuang - harus memicu warning
return 0;
}Compile dan amati warning yang muncul:
gcc -std=c2x -Wall -Wextra -pedantic -o c23_2b c23_2b.cOutput yang Dihasilkan:
c23_2b.c: In function 'main':
c23_2b.c:9:5: warning: ignoring return value of 'hitung_total', declared with attribute 'nodiscard' [-Wunused-result]
9 | hitung_total(data, 3); // hasil dibuang - harus memicu warning
| ^~~~~~~~~~~~~~~~~~~~~
c23_2b.c:2:19: note: declared here
2 | [[nodiscard]] int hitung_total(int *arr, int n) {
| ^~~~~~~~~~~~Attribute [[nodiscard]] sangat berguna untuk fungsi yang return value-nya penting (mis. alokator, error code, atau hasil komputasi mahal). Attribute [[deprecated]] memberi pesan migrasi yang jelas saat API berubah. Attribute [[maybe_unused]] menggantikan trik (void)x; lama untuk menekan warning variabel tidak terpakai.
typeof, auto, dan #embed #
C23 mempromosikan beberapa ekstensi GCC menjadi standar resmi: typeof (mengambil tipe dari ekspresi), auto (type inference untuk variabel lokal), dan #embed (memasukkan file binary sebagai initializer). Program berikut memperlihatkan typeof dan auto:
// File: c23_3.c - typeof dan auto sebagai keyword standar
#include <stdio.h>
// typeof: jadi keyword resmi di C23 (sebelumnya ekstensi GCC)
static int jumlah_array(int n, typeof(int) *arr) {
typeof(int) total = 0;
for (int i = 0; i < n; ++i) {
total += arr[i];
}
return total;
}
// auto: type inference untuk variabel lokal
static int demo_auto(void) {
auto x = 42; // int
auto y = 3.14; // double
auto z = "halo"; // const char *
(void)z;
return x + (int)y;
}
int main(void) {
int data[] = {10, 20, 30, 40};
printf("Jumlah : %d\n", jumlah_array(4, data));
printf("demo_auto: %d\n", demo_auto());
return 0;
}Compile dan jalankan:
gcc -std=c2x -Wall -Wextra -pedantic -o c23_3 c23_3.c
./c23_3Output yang Dihasilkan:
Jumlah : 100
demo_auto: 45