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.

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

text
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 = 0x0000000430E23400

Mari kita telaah baris-baris kode di atas:

  1. Baris 14 ("%" PRId32 "\n"): tiga string literal ("%", PRId32 yang expand ke "d" di LP64, dan "\n") digabung kompiler menjadi satu "%d\n". Pada platform di mana int32_t adalah long, makro PRId32 akan expand ke "ld", sehingga format final "%ld\n".
  2. Baris 18 ("%" PRIdMAX "\n"): makro PRIdMAX selalu benar untuk intmax_t. Berguna saat kita menulis kode generik yang menerima tipe apa pun—konversi ke intmax_t dulu, lalu cetak dengan PRIdMAX.
  3. Baris 22 ("0x%08" PRIX32): makro PRIX32 menghasilkan hex huruf KAPITAL (lihat X di nama makro). Modifier %08 memaksa lebar minimum 8 karakter dengan zero-padding. Untuk hex huruf kecil, gunakan PRIx32.
  4. Baris 23 ("0x%016" PRIX64): uint64_t memerlukan 16 digit hex penuh, makanya %016 untuk 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.

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

text
Parsed int32_t = 42
Parsed uint64_t = 18446744073709551615
Parsed x=100, y=-2000000000, jumlah=-1999999900

Makro 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.

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

text
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") = 18446744073709551615

Fungsi 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.