Untuk menulis kode yang aman terhadap integer overflow, kita perlu tahu batas nilai setiap tipe. Hard-coding batas seperti 2147483647 sangat rentan kesalahan dan tidak portabel. Standar C menyediakan header <limits.h> untuk batas tipe integer dan <float.h> untuk batas tipe floating point. Kedua header ini berisi makro praproses yang nilainya disesuaikan compiler dengan ukuran tipe aktual di platform. Pada Chapter ini kita akan memetakan konstanta-konstanta tersebut dan melihat bagaimana menggunakannya untuk pemeriksaan rentang yang aman.

Konstanta limits.h untuk Tipe Integer #

Header <limits.h> mendefinisikan makro yang menyatakan batas minimum dan maksimum setiap tipe integer. Daftar lengkap konstanta yang paling sering dipakai:

MakroTipeNilai (x86_64)
CHAR_BITbit per char8
SCHAR_MIN/SCHAR_MAXsigned char-128 / 127
UCHAR_MAXunsigned char255
SHRT_MIN/SHRT_MAXshort-32.768 / 32.767
USHRT_MAXunsigned short65.535
INT_MIN/INT_MAXint-2.147.483.648 / 2.147.483.647
UINT_MAXunsigned int4.294.967.295
LONG_MIN/LONG_MAXlong-9.223.372.036.854.775.808 / 9.223.372.036.854.775.807
ULONG_MAXunsigned long18.446.744.073.709.551.615
LLONG_MIN/LLONG_MAXlong long-9.223.372.036.854.775.808 / 9.223.372.036.854.775.807
ULLONG_MAXunsigned long long18.446.744.073.709.551.615
c
#include <stdio.h>
#include <limits.h>

int main(void) {
    printf("Konstanta limits.h untuk tipe integer:\n");
    printf("CHAR_BIT = %d  (bit per char)\n", CHAR_BIT);
    printf("SCHAR_MIN = %d, SCHAR_MAX = %d\n", SCHAR_MIN, SCHAR_MAX);
    printf("UCHAR_MAX = %u\n", UCHAR_MAX);
    printf("SHRT_MIN  = %d, SHRT_MAX  = %d\n", SHRT_MIN, SHRT_MAX);
    printf("USHRT_MAX = %u\n", USHRT_MAX);
    printf("INT_MIN   = %d\n", INT_MIN);
    printf("INT_MAX   = %d\n", INT_MAX);
    printf("UINT_MAX  = %u\n", UINT_MAX);
    printf("LONG_MIN  = %ld\n", LONG_MIN);
    printf("LONG_MAX  = %ld\n", LONG_MAX);
    printf("ULONG_MAX = %lu\n", ULONG_MAX);
    printf("LLONG_MIN = %lld\n", LLONG_MIN);
    printf("LLONG_MAX = %lld\n", LLONG_MAX);
    printf("ULLONG_MAX = %llu\n", ULLONG_MAX);
    return 0;
}

Output yang Dihasilkan:

text
Konstanta limits.h untuk tipe integer:
CHAR_BIT = 8  (bit per char)
SCHAR_MIN = -128, SCHAR_MAX = 127
UCHAR_MAX = 255
SHRT_MIN  = -32768, SHRT_MAX  = 32767
USHRT_MAX = 65535
INT_MIN   = -2147483648
INT_MAX   = 2147483647
UINT_MAX  = 4294967295
LONG_MIN  = -9223372036854775808
LONG_MAX  = 9223372036854775807
ULONG_MAX = 18446744073709551615
LLONG_MIN = -9223372036854775808
LLONG_MAX = 9223372036854775807
ULLONG_MAX = 18446744073709551615

Mari kita telaah baris-baris kode di atas:

  1. Baris 2 (#include <limits.h>): menyertakan header yang mendefinisikan seluruh makro batas tipe integer.
  2. Baris 6 (CHAR_BIT): jumlah bit per char; dijamin minimal 8 oleh standar, hampir selalu persis 8 di platform modern.
  3. Baris 7-8 (SCHAR_* dan UCHAR_MAX): batas tipe signed char dan unsigned char. Perhatikan tidak ada CHAR_MIN/CHAR_MAX generik karena char bisa bertanda atau tidak tergantung compiler.
  4. Baris 11-12 (INT_MIN, INT_MAX): batas tipe int 4 byte—rentang -2^31 hingga 2^31-1.
  5. Baris 15 (LLONG_MAX): batas atas long long, yaitu 2^63-1; nilai ini sama dengan LONG_MAX di platform LP64 (Linux/macOS x86_64).

Konstanta float.h untuk Tipe Floating Point #

Header <float.h> menyediakan konstanta untuk tipe floating point. Yang paling sering dipakai:

MakroTipeMakna
FLT_MIN / DBL_MIN / LDBL_MINfloat/double/long doubleNilai positif terkecil (bukan nol)
FLT_MAX / DBL_MAX / LDBL_MAXNilai positif terbesar
FLT_EPSILON / DBL_EPSILON / LDBL_EPSILONSelisih antara 1.0 dan nilai terkecil berikutnya
FLT_DIG / DBL_DIG / LDBL_DIGJumlah digit desimal yang dijamin akurat
c
#include <stdio.h>
#include <limits.h>
#include <float.h>

int main(void) {
    printf("Konstanta float.h:\n");
    printf("FLT_MIN    = %e  (min positive)\n", FLT_MIN);
    printf("FLT_MAX    = %e\n", FLT_MAX);
    printf("FLT_EPSILON = %e\n", FLT_EPSILON);
    printf("FLT_DIG    = %d  (digit desimal akurat)\n", FLT_DIG);
    printf("DBL_MIN    = %e\n", DBL_MIN);
    printf("DBL_MAX    = %e\n", DBL_MAX);
    printf("DBL_EPSILON = %e\n", DBL_EPSILON);
    printf("DBL_DIG    = %d\n", DBL_DIG);
    return 0;
}

Output yang Dihasilkan:

text
Konstanta float.h:
FLT_MIN    = 1.175494e-38  (min positive)
FLT_MIN    = 3.402823e+38
FLT_EPSILON = 1.192093e-07
FLT_DIG    = 6  (digit desimal akurat)
DBL_MIN    = 2.225074e-308
DBL_MAX    = 1.797693e+308
DBL_EPSILON = 2.220446e-16
DBL_DIG    = 15

Pada baris 7, FLT_MIN adalah nilai positif terkecil yang bisa direpresentasikan float (sekitar 1.18 × 10^-38), bukan nol atau bilangan negatif. Pada baris 8, FLT_MAX adalah nilai positif terbesar (sekitar 3.4 × 10^38). Pada baris 9, FLT_EPSILON menunjukkan presisi mesin: selisih antara 1.0f dan float terkecil yang lebih besar dari 1.0f. Pada baris 10, FLT_DIG = 6 berarti float hanya dijamin akurat untuk 6 digit desimal; sisanya bisa berubah karena pembulatan.

Memakai limits.h untuk Pemeriksaan Rentang #

Manfaat utama <limits.h> adalah memungkinkan pemeriksaan rentang secara aman sebelum melakukan cast atau operasi yang berisiko overflow. Sebagai contoh, sebelum mengubah long ke int, kita perlu memastikan nilainya berada dalam rentang INT_MIN hingga INT_MAX.

c
#include <stdio.h>
#include <limits.h>

int main(void) {
    /* Memeriksa rentang input sebelum diproses */
    long nilai = 5000000L;

    if (nilai >= INT_MIN && nilai <= INT_MAX) {
        int aman = (int)nilai;
        printf("nilai %ld muat di int: %d\n", nilai, aman);
    } else {
        printf("nilai %ld tidak muat di int\n", nilai);
    }

    /* Kasus overflow potensial */
    long besar = (long)INT_MAX + 100L;
    if (besar >= INT_MIN && besar <= INT_MAX) {
        printf("besar muat di int\n");
    } else {
        printf("besar = %ld tidak muat di int (INT_MAX = %d)\n",
               besar, INT_MAX);
    }
    return 0;
}

Output yang Dihasilkan:

text
nilai 5000000 muat di int: 5000000
besar = 2147483747 tidak muat di int (INT_MAX = 2147483647)

Pada baris 9, nilai 5.000.000 berada dalam rentang INT_MIN/INT_MAX sehingga cast ke int aman dilakukan. Pada baris 17, besar dihitung sebagai INT_MAX + 100, yaitu 2.147.483.747, yang melebihi INT_MAX. Karena pemeriksaan rentang dilakukan lebih dulu, cabang else yang dieksekusi dan tidak ada cast berbahaya yang terjadi. Pola ini harus menjadi kebiasaan setiap kali kita melakukan konversi antar tipe yang ukurannya berbeda.

Dengan kedua header <limits.h> dan <float.h>, kita punya referensi resmi untuk seluruh batas tipe. Selanjutnya, kita akan mempelajari cara mendefinisikan konstanta sendiri lewat #define dan keyword const.