Header <inttypes.h> adalah pasangan wajib untuk <stdint.h>. Tipe seperti int32_t dan uint64_t memberi jaminan ukuran, tetapi format specifier untuk printf/scanf bervariasi antar platform: int32_t bisa int, long, atau int di tergantung ABI. Header <inttypes.h> menyediakan makro PRId32, PRIu64, SCNd32, SCNu64 yang di-expand ke specifier benar untuk platform. Selain makro format, header ini juga menyediakan fungsi strtoimax/strtoumax untuk mengkonversi string ke intmax_t/uintmax_t. Pada chapter ini kita akan meninjau penggunaan makro PRI* untuk printf, SCN* untuk scanf, dan fungsi strtoimax/strtoumax.
Makro PRI* untuk printf #
Makro PRId32, PRIu64, PRIX32, dan kawan-kawan di-expand ke string literal pendek seperti "d", "ld", atau "lld" tergantung bagaimana tipe tersebut didefinisikan di platform. Pola pemakaian: printf("%" PRId32 "\n", nilai);—kompiler menggabungkan dua string literal yang berdekatan menjadi satu format string utuh.
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
int main(void) {
int32_t i32 = -1234567;
uint32_t u32 = 4000000000U;
int64_t i64 = -9876543210LL;
uint64_t u64 = 18000000000ULL;
intmax_t imx = 123456789012345LL;
/* Format specifier portabel untuk stdint types */
printf("int32_t via PRId32 = %" PRId32 "\n", i32);
printf("uint32_t via PRIu32 = %" PRIu32 "\n", u32);
printf("int64_t via PRId64 = %" PRId64 "\n", i64);
printf("uint64_t via PRIu64 = %" PRIu64 "\n", u64);
printf("intmax_t via PRIdMAX = %" PRIdMAX "\n", imx);
/* Hex dengan lebar tetap */
printf("\nHex dari u32 = 0x%08" PRIX32 "\n", u32);
printf("Hex dari u64 = 0x%016" PRIX64 "\n", u64);
return 0;
}Output yang Dihasilkan:
int32_t via PRId32 = -1234567
uint32_t via PRIu32 = 4000000000
int64_t via PRId64 = -9876543210
uint64_t via PRIu64 = 18000000000
intmax_t via PRIdMAX = 123456789012345
Hex dari u32 = 0xEE6B2800
Hex dari u64 = 0x0000000430E23400Mari kita telaah baris-baris kode di atas:
- Baris 14 (
"%" PRId32 "\n"): tiga string literal ("%",PRId32yang expand ke"d"di LP64, dan"\n") digabung kompiler menjadi satu"%d\n". Pada platform di manaint32_tadalahlong, makroPRId32akan expand ke"ld", sehingga format final"%ld\n". - Baris 18 (
"%" PRIdMAX "\n"): makroPRIdMAXselalu benar untukintmax_t. Berguna saat kita menulis kode generik yang menerima tipe apa pun—konversi keintmax_tdulu, lalu cetak denganPRIdMAX. - Baris 22 (
"0x%08" PRIX32): makroPRIX32menghasilkan hex huruf KAPITAL (lihatXdi nama makro). Modifier%08memaksa lebar minimum 8 karakter dengan zero-padding. Untuk hex huruf kecil, gunakanPRIx32. - Baris 23 (
"0x%016" PRIX64):uint64_tmemerlukan 16 digit hex penuh, makanya%016untuk zero-padding 16 karakter.
Makro SCN* untuk scanf #
Makro SCNd32, SCNu64, dan kawan-kawan adalah pasangan scanf untuk PRI*. Pola pemakaian sama: sscanf(buf, "%" SCNd32, &val);. SCN* diperlukan karena scanf lebih ketat dari printf—ukuran argumen pointer harus persis cocok dengan specifier untuk menghindari undefined behavior.
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
int main(void) {
int32_t a;
uint64_t b;
/* SCNd32 = scanf specifier untuk int32_t */
const char *input1 = "42";
if (sscanf(input1, "%" SCNd32, &a) == 1) {
printf("Parsed int32_t = %" PRId32 "\n", a);
}
/* SCNu64 = scanf specifier untuk uint64_t */
const char *input2 = "18446744073709551615";
if (sscanf(input2, "%" SCNu64, &b) == 1) {
printf("Parsed uint64_t = %" PRIu64 "\n", b);
}
/* Demo: gabungkan dua specifier dalam satu format */
const char *input3 = "100 -2000000000";
int32_t x, y;
if (sscanf(input3, "%" SCNd32 " %" SCNd32, &x, &y) == 2) {
printf("Parsed x=%" PRId32 ", y=%" PRId32 ", jumlah=%" PRId32 "\n",
x, y, x + y);
}
return 0;
}Output yang Dihasilkan:
Parsed int32_t = 42
Parsed uint64_t = 18446744073709551615
Parsed x=100, y=-2000000000, jumlah=-1999999900Makro SCNd32 mengkonversi input ke int32_t signed (mendukung tanda minus). Makro SCNu64 mengkonversi ke uint64_t unsigned (tidak ada tanda, nilai negatif menjadi wrap-around). Pada baris 21, dua makro SCNd32 digabung dengan spasi literal di tengah—scanf otomatis melewatkan whitespace apapun di input. Return value sscanf adalah jumlah konversi yang berhasil, jadi == 2 memverifikasi kedua nilai berhasil diparse. Hasil x + y = -1999999900 berada dalam rentang int32_t (min -2147483648), jadi tidak terjadi overflow.
Konversi String ke intmax_t dengan strtoimax #
Selain makro format, <inttypes.h> juga menyediakan strtoimax dan strtoumax—versi intmax_t/uintmax_t dari strtol/strtoul. Fungsi-fungsi ini berguna saat kita perlu mengkonversi angka yang mungkin sangat besar (lebih besar dari long), atau saat kita ingin parsing yang konsisten tanpa peduli platform.
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
/* strtoimax dan strtoumax: konversi string ke intmax_t/uintmax_t */
int main(void) {
const char *s1 = "1234567890123456789";
const char *s2 = "0xFF"; /* heksadesimal */
const char *s4 = " -42abc"; /* whitespace + suffix invalid */
char *endp = NULL;
intmax_t v1 = strtoimax(s1, &endp, 10);
printf("strtoimax(\"%s\", base 10) = %" PRIdMAX " (sisa=\"%s\")\n",
s1, v1, endp);
intmax_t v2 = strtoimax(s2, &endp, 16);
printf("strtoimax(\"%s\", base 16) = %" PRIdMAX " (sisa=\"%s\")\n",
s2, v2, endp);
/* base 0 = auto-detect dari prefix: 0x=hex, 0=octal, lain=desimal */
intmax_t v3 = strtoimax(s2, &endp, 0);
printf("strtoimax(\"%s\", base 0) = %" PRIdMAX " (auto-detect hex)\n",
s2, v3);
/* strtoimax otomatis skip whitespace awal */
intmax_t v4 = strtoimax(s4, &endp, 10);
printf("strtoimax(\"%s\", base 10) = %" PRIdMAX " (sisa=\"%s\")\n",
s4, v4, endp);
/* Bandingkan dengan uintmax_t untuk rentang yang lebih luas */
uintmax_t uv = strtoumax("18446744073709551615", NULL, 10);
printf("\nstrtoumax(\"18446744073709551615\") = %" PRIuMAX "\n", uv);
return 0;
}Output yang Dihasilkan:
strtoimax("1234567890123456789", base 10) = 1234567890123456789 (sisa="")
strtoimax("0xFF", base 16) = 255 (sisa="")
strtoimax("0xFF", base 0) = 255 (auto-detect hex)
strtoimax(" -42abc", base 10) = -42 (sisa="abc")
strtoumax("18446744073709551615") = 18446744073709551615Fungsi strtoimax(s, &endp, base) mengkonversi awal string s ke intmax_t. Parameter base menentukan basis numerik: 10 desimal, 16 heksadesimal, 2 biner, 8 oktal, atau 0 untuk auto-detect berdasarkan prefix (0x hex, 0 octal, lainnya desimal). Pointer endp diisi dengan alamat karakter pertama yang tidak ikut diparse—berguna untuk validasi input. String " -42abc" menunjukkan tiga fitur sekaligus: strtoimax otomatis skip whitespace awal, mengenali tanda minus, dan berhenti di karakter non-digit ('a'), menyisakan "abc" di endp. Fungsi strtoumax adalah padanan unsigned—rentang hingga 2^64 - 1.