C99 (ISO/IEC 9899:1999) adalah lompatan fitur terbesar dalam sejarah C setelah standarisasi C89. Standar ini menjawab kebutuhan praktis programmer: komentar // yang lebih ringkas, deklarasi variabel di tengah blok (mixed declaration) untuk membaca lebih dekat ke penggunaan, tipe integer dengan lebar eksak (uint32_t, int64_t) lewat header stdint.h, tipe boolean asli (bool) lewat stdbool.h, type long long 64-bit, variable-length array (VLA), designated initializer, compound literal, dan inline function. Bab ini menunjukkan setiap fitur tersebut dengan kode yang di-compile menggunakan gcc -std=c99 -pedantic, agar kita yakin kode benar-benar memakai C99 murni dan bukan ekstensi GCC. Kita juga akan melihat bagaimana fitur-fitur ini mengubah gaya penulisan C dari gaya verbose C89 menjadi lebih ringkas dan ekspresif.
Komentar //, Mixed Declaration, dan Designated Initializer #
Tiga perubahan paling terasa dari C89 ke C99 adalah sintaksis keseharian: komentar satu baris //, deklarasi variabel di mana pun di dalam blok, dan designated initializer yang memungkinkan kita menyebut field struct berdasarkan nama saat inisialisasi. Ketiganya membuat kode jauh lebih ringkas dan membaca lebih dekat ke penggunaan variabel.
// File: c99_1.c - Fitur khas C99: // komentar, mixed declaration, designated initializer
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct {
char nama[32];
int umur;
bool lulus;
} Siswa;
int main(void) {
// designated initializer: sebut field by name
Siswa daftar[3] = {
[0] = { .nama = "Budi", .umur = 17, .lulus = true },
[1] = { .nama = "Siti", .umur = 18, .lulus = true },
[2] = { .nama = "Andi", .umur = 16, .lulus = false }
};
printf("%-6s %-4s %s\n", "Nama", "Umur", "Lulus");
printf("%-6s %-4s %s\n", "----", "----", "-----");
for (int i = 0; i < 3; ++i) { // deklarasi i di dalam for
printf("%-6s %-4d %s\n",
daftar[i].nama,
daftar[i].umur,
daftar[i].lulus ? "ya" : "tidak");
}
// Tipe integer width-exact dari stdint.h
uint32_t harga = 1500000u;
int64_t populasi_dunia = 7900000000LL;
printf("\nHarga : %u\n", harga);
printf("Populasi dunia: %lld\n", (long long)populasi_dunia);
return 0;
}Compile dan jalankan:
gcc -std=c99 -Wall -Wextra -pedantic -o c99_1 c99_1.c
./c99_1Output yang Dihasilkan:
Nama Umur Lulus
---- ---- -----
Budi 17 ya
Siti 18 ya
Andi 16 tidak
Harga : 1500000
Populasi dunia: 7900000000Mari kita telaah baris-baris kode di atas:
- Baris 1 (
// File: c99_1.c ...): Komentar satu baris dengan//, ilegal di C89 tetapi sah di C99. Tanpa-std=c99, GCC menerima//sebagai ekstensi; dengan-std=c89 -pedantickomentar ini akan jadi error. - Baris 15-19 (
Siswa daftar[3] = { [0] = {...}, [1] = {...}, [2] = {...} };): Designated initializer. Kita sebut index array[0],[1],[2]dan field struct.nama,.umur,.lulussecara eksplisit. Inisialisasi tidak perlu mengikuti urutan field, dan field yang tidak disebut otomatis di-zero. - Baris 24 (
for (int i = 0; ...)): Deklarasiint idi dalam statementfor. Di C89,iharus dideklarasikan di awal blokmain. C99 mengizinkan deklarasi di mana pun dalam blok, termasuk di dalam clausefor. - Baris 33 (
uint32_t harga = 1500000u;): Tipe integer dengan lebar eksak 32-bit daristdint.h. Di C89, kita hanya punyaint,long,shortyang lebarnya bergantung platform. Denganuint32_t, kode portable dijamin ukurannya. - Baris 34 (
int64_t populasi_dunia = 7900000000LL;): Tipelong long64-bit baru di C99, dengan literalLL. TanpaLL, angka sebesar 7.9 miliar tidak muat di 32-bitintdan akan terpotong.
VLA dan Compound Literal #
Variable-Length Array (VLA) memungkinkan array dengan ukuran yang baru diketahui saat runtime, diambil dari variabel biasa. Compound literal memungkinkan kita membuat struct atau array tanpa nama variabel, langsung di ekspresi. Kedua fitur ini membuat C99 lebih fleksibel untuk kode numerik dan prototyping cepat.
// File: c99_2.c - VLA dan compound literal
#include <stdio.h>
static int jumlah_vla(int n) {
int buf[n]; // VLA: ukuran dari variabel runtime
for (int i = 0; i < n; ++i) {
buf[i] = i * i;
}
int total = 0;
for (int i = 0; i < n; ++i) {
total += buf[i];
}
return total;
}
int main(void) {
int n = 5;
printf("Jumlah kuadrat 0..%d: %d\n", n - 1, jumlah_vla(n));
// compound literal: membuat struct sementara in-place
struct Koord { int x; int y; };
struct Koord titik = (struct Koord){ .x = 3, .y = 4 };
printf("Titik: (%d, %d), jarak^2 = %d\n",
titik.x, titik.y, titik.x * titik.x + titik.y * titik.y);
// compound literal untuk array
int *arr = (int[]){10, 20, 30, 40};
for (int i = 0; i < 4; ++i) {
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}Compile dan jalankan:
gcc -std=c99 -Wall -Wextra -pedantic -o c99_2 c99_2.c
./c99_2Output yang Dihasilkan:
Jumlah kuadrat 0..4: 30
Titik: (3, 4), jarak^2 = 25
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40Fungsi jumlah_vla menerima parameter n dan membuat array lokal buf[n] dengan ukuran yang baru diketahui saat pemanggilan. VLA disimpan di stack dengan ukuran dinamis—ini berbeda dengan malloc yang menggunakan heap. VLA nyaman untuk buffer sementara yang ukurannya kecil dan hanya hidup dalam satu fungsi. Compound literal (struct Koord){ .x = 3, .y = 4 } dan (int[]){10, 20, 30, 40} membuat objek tanpa harus mendeklarasikan variabel terlebih dahulu—berguna untuk passing argumen ke fungsi yang menerima pointer.
Inline Function dan long long #
C99 formalisasi keyword inline (sebelumnya ekstensi C++ di banyak compiler) dan menambahkan tipe long long (minimal 64-bit). Program berikut memperlihatkan keduanya:
// File: c99_3.c - inline function dan long long
#include <stdio.h>
static inline int kuadrat(int x) {
return x * x;
}
int main(void) {
long long besar = 9000000000LL; // 64-bit integer literal
printf("Kuadrat 7 : %d\n", kuadrat(7));
printf("Long long besar: %lld\n", besar);
return 0;
}Compile dan jalankan:
gcc -std=c99 -Wall -Wextra -pedantic -o c99_3 c99_3.c
./c99_3Output yang Dihasilkan:
Kuadrat 7 : 49
Long long besar: 9000000000Keyword inline memberi tahu compiler bahwa pemanggilan fungsi kuadrat dapat diganti dengan badan fungsi secara langsung (inlined) untuk efisiensi. Tipe long long menjamin minimal 64-bit, sedangkan literal 9000000000LL diakhiri LL agar diproses sebagai long long. Pada arsitektur 32-bit lama, int hanya 32-bit sehingga angka 9 miliar tidak muat—long long menyelesaikan ini tanpa kode platform-specific.