C Standard Library limits.h

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
<limits.h>

What You’ll Learn

The <limits.h> header defines macros for the minimum and maximum values of integer types—char, short, int, long, and their unsigned variants. It also defines CHAR_BIT, the number of bits in a byte. Use these constants to avoid overflow and write portable code.

01

INT_MAX

Largest int.

02

INT_MIN

Smallest int.

03

CHAR_BIT

Bits/byte.

04

UINT_MAX

Max unsigned.

05

LONG_MAX

Long range.

06

Portable

Use macros.

Definition and Usage

Every integer type has a finite range. Adding 1 to INT_MAX overflows; subtracting 1 from INT_MIN underflows. The C standard does not fix how many bits an int has—that depends on the compiler and platform—but <limits.h> always tells you the limits for your build.

Macros use a naming pattern: TYPE_MAX and TYPE_MIN for signed types, and UTYPE_MAX for unsigned types (minimum is always 0). Prefixes include SCHAR_, SHRT_, INT_, LONG_, and LLONG_ (C99).

💡
Beginner Tip

The old reference showed #define INT_MAX 2147483647 as if you write those lines yourself. You include <limits.h> and read the macros—never redefine them in your program.

📝 Syntax

Include the header:

C
#include <limits.h>

Character and byte

  • CHAR_BIT — bits in a char (typically 8).
  • SCHAR_MIN / SCHAR_MAX — range of signed char.
  • UCHAR_MAX — maximum unsigned char (often 255).
  • CHAR_MIN / CHAR_MAX — range of plain char (signedness implementation-defined).

Signed integer types

  • SHRT_MIN / SHRT_MAXshort.
  • INT_MIN / INT_MAXint.
  • LONG_MIN / LONG_MAXlong.
  • LLONG_MIN / LLONG_MAXlong long (C99).

Unsigned integer types

  • USHRT_MAX, UINT_MAX, ULONG_MAX, ULLONG_MAX.
  • Unsigned minimum is always 0 (no UINT_MIN macro).

Typical values (32-bit int platform)

C
/* Examples only — use macros from limits.h, not literals */
CHAR_BIT     /* often 8 */
SCHAR_MIN    /* often -128 */
SCHAR_MAX    /* often 127 */
UCHAR_MAX    /* often 255 */
INT_MIN      /* often -2147483648 */
INT_MAX      /* often 2147483647 */
UINT_MAX     /* often 4294967295 */

Headers and linking

  • #include <limits.h> — macros only, no link flag.
  • For fixed-width types, also see <stdint.h> (INT32_MAX, etc.).
  • For floating limits, see <float.h>.
  • Compile: gcc program.c -std=c11 -o program

⚡ Quick Reference

MacroTypeTypical role
CHAR_BITcharBits per byte (usually 8)
INT_MAXintUpper bound for int
INT_MINintLower bound for int
UINT_MAXunsigned intMax unsigned int
LONG_MAXlongPlatform-dependent (32 or 64 bit)
UCHAR_MAXunsigned char0–255 on 8-bit char systems
Overflow
if (a > INT_MAX - b)

Safe add check

Bits
sizeof(int)*CHAR_BIT

int bit width

Print
printf("%u", UINT_MAX)

Unsigned format

Validate
x >= INT_MIN && x <= INT_MAX

Range check

Examples Gallery

Compile with gcc file.c -std=c11 -o out. Sample output matches typical GCC on a 64-bit system with 32-bit int and 64-bit long.

📚 Getting Started

See what your compiler reports for each integer type.

Example 1 — Print Integer Type Ranges

From the reference, with complete output and correct printf formats for unsigned types.

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

int main(void) {
    printf("CHAR_BIT = %d\n\n", CHAR_BIT);

    printf("signed char:   %d to %d\n", SCHAR_MIN, SCHAR_MAX);
    printf("unsigned char: 0 to %u\n", UCHAR_MAX);
    printf("short:         %d to %d\n", SHRT_MIN, SHRT_MAX);
    printf("unsigned short:0 to %u\n", USHRT_MAX);
    printf("int:           %d to %d\n", INT_MIN, INT_MAX);
    printf("unsigned int:  0 to %u\n", UINT_MAX);
    printf("long:          %ld to %ld\n", LONG_MIN, LONG_MAX);
    printf("unsigned long: 0 to %lu\n", ULONG_MAX);

    return 0;
}

How It Works

The old reference output showed only the last three lines. Here every type is printed. Use %u / %lu for unsigned macros so values display correctly.

Example 2 — Safe Addition Before Overflow

Check whether a + b would exceed INT_MAX before adding.

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

int safe_add(int a, int b, int *out) {
    if (b > 0 && a > INT_MAX - b) {
        return -1;  /* overflow */
    }
    if (b < 0 && a < INT_MIN - b) {
        return -1;  /* underflow */
    }
    *out = a + b;
    return 0;
}

int main(void) {
    int result;

    if (safe_add(INT_MAX, 1, &result) != 0) {
        printf("Overflow avoided: INT_MAX + 1 does not fit in int\n");
    } else {
        printf("Result: %d\n", result);
    }

    return 0;
}

How It Works

Instead of hard-coding 2147483647, use INT_MAX. The check a > INT_MAX - b detects overflow before it happens. Production code on GCC may use built-ins like __builtin_add_overflow; this pattern teaches the idea.

📈 Practical Patterns

Measure types, validate input, and compare sizes.

Example 3 — CHAR_BIT and sizeof

Compute how many bits each integer type uses on your platform.

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

int main(void) {
    printf("CHAR_BIT = %d bits per byte\n", CHAR_BIT);
    printf("sizeof(char)  = %zu byte  (%zu bits)\n",
           sizeof(char), sizeof(char) * CHAR_BIT);
    printf("sizeof(short) = %zu bytes (%zu bits)\n",
           sizeof(short), sizeof(short) * CHAR_BIT);
    printf("sizeof(int)   = %zu bytes (%zu bits)\n",
           sizeof(int), sizeof(int) * CHAR_BIT);
    printf("sizeof(long)  = %zu bytes (%zu bits)\n",
           sizeof(long), sizeof(long) * CHAR_BIT);

    return 0;
}

How It Works

CHAR_BIT converts byte counts from sizeof into bit widths. This explains why INT_MAX is about 2×109 on a 32-bit int system.

Example 4 — Validate a Value Fits in int

Reject numbers outside INT_MININT_MAX before storing in an int.

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

int fits_in_int(long value) {
    return value >= INT_MIN && value <= INT_MAX;
}

int main(void) {
    long candidates[] = { 100L, 2147483647L, 3000000000L };

    for (size_t i = 0; i < 3; i++) {
        long v = candidates[i];
        printf("%ld: %s\n", v,
               fits_in_int(v) ? "fits in int" : "too large for int");
    }

    return 0;
}

How It Works

3000000000 exceeds INT_MAX (2147483647 on typical systems). Comparing against macros keeps the check portable if int size changes.

Example 5 — Compare limits.h with sizeof

See how macro ranges relate to type sizes—and why you need both headers for different jobs.

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

int main(void) {
    printf("limits.h says:\n");
    printf("  INT_MAX  = %d\n", INT_MAX);
    printf("  UINT_MAX = %u\n", UINT_MAX);

    printf("\nsizeof says:\n");
    printf("  int          = %zu bytes\n", sizeof(int));
    printf("  unsigned int = %zu bytes\n", sizeof(unsigned int));

    printf("\nRule of thumb: %zu-byte int holds roughly %d decimal digits.\n",
           sizeof(int), (int)(sizeof(int) * CHAR_BIT * 0.301) + 1);

    return 0;
}

How It Works

limits.h gives exact min/max values; sizeof gives storage size. For fixed 32-bit integers regardless of platform, use <stdint.h> and int32_t instead.

🚀 Common Use Cases

  • Overflow checks — validate sums, products, and array index math.
  • Input validation — ensure parsed numbers fit the target type.
  • Buffer sizing — use UCHAR_MAX + 1 (256) for byte tables when char is 8 bits.
  • Portable constants — replace magic numbers in algorithms.
  • Serialization — pick the narrowest type that fits a value range.
  • Embedded systems — confirm int width before porting desktop code.

🧠 How limits.h Works

1

Include limits.h

Compiler provides macros matching its integer model.

Setup
2

Read TYPE_MAX/MIN

Constants expand at compile time—no runtime lookup.

Constants
3

Guard operations

Compare inputs and intermediate results against limits.

Protect
=

Portable integer code

Same source adapts when long is 32 or 64 bits.

📝 Notes

  • Macro values are implementation-defined—never hard-code 2147483647.
  • char may be signed or unsigned; use signed char / unsigned char when sign matters.
  • Unsigned overflow wraps modulo UTYPE_MAX + 1; signed overflow is undefined behavior.
  • INT_MIN often has no positive counterpart (e.g. -2147483648).
  • C99 adds LLONG_* macros for long long.
  • For floating-point limits, use <float.h>, not limits.h.

⚡ Optimization

Limit macros compile to constants—zero runtime cost. Choose the smallest type that fits your data (unsigned char for 0–255) to save memory in large arrays. Overflow checks add branches; keep them on untrusted input paths, not every inner-loop increment.

Conclusion

<limits.h> is the portable way to learn how big your integer types are on any platform. Use INT_MAX, INT_MIN, UINT_MAX, and CHAR_BIT for range checks, validation, and clear code.

Pair it with <stdint.h> when you need exact bit widths, and <float.h> for floating-point limits.

💡 Best Practices

✅ Do

  • Use INT_MAX / INT_MIN macros, not literals
  • Match printf format to signed vs unsigned
  • Check overflow before arithmetic on untrusted data
  • Use signed char when you need negative bytes
  • Print limits once on a new platform during porting

❌ Don’t

  • Redefine #define INT_MAX in your own code
  • Assume int is always 32 bits
  • Print UINT_MAX with %d
  • Confuse CHAR_MAX with SCHAR_MAX blindly
  • Rely on signed integer overflow “wrapping” (undefined in C)

Key Takeaways

Knowledge Unlocked

Five things to remember about limits.h

Integer limits in C, explained simply.

5
Core concepts
📚 02

CHAR_BIT

Bits/byte.

Size
📈 03

UINT_MAX

Unsigned.

Format %u
📄 04

Overflow

Check first.

Safety
🌐 05

Portable

Use macros.

Platform

❓ Frequently Asked Questions

limits.h defines implementation-specific macros for integer type limits: minimum and maximum values for char, short, int, long, and their unsigned forms, plus CHAR_BIT (bits per char). Use these macros instead of hard-coding numbers like 2147483647.
SCHAR_MIN and SCHAR_MAX always refer to signed char. CHAR_MIN and CHAR_MAX refer to plain char, which may be signed or unsigned depending on the compiler. On many systems char is signed; on others it is unsigned—use SCHAR_* when you need signed char specifically.
No. An int might be 16 bits on embedded systems and 32 bits on desktops. LONG_MAX differs between 32-bit and 64-bit Windows vs Linux. Always use the macros from limits.h on your target platform.
limits.h names limits after fundamental types (INT_MAX, LONG_MAX). stdint.h provides fixed-width types (int32_t) and matching limits (INT32_MAX). Use limits.h for portable code with int/long; use stdint.h when you need exact bit widths.
CHAR_BIT is the number of bits in a byte (char). It is at least 8 on all standard C implementations and is almost always exactly 8. Use CHAR_BIT with sizeof to compute bit sizes: sizeof(int) * CHAR_BIT.
UINT_MAX is an unsigned int. Printing it with %d treats the value as signed and can show a negative number on some platforms. Match the printf format to the type: %d for signed, %u for unsigned, %lu for unsigned long.
Did you know?

On many 64-bit systems, int is still 32 bits while long is 64 bits—but on Windows LLP64, long remains 32 bits and only long long is 64 bits. That is exactly why limits.h exists: the same source file can print different LONG_MAX values on different targets without changing a single literal in your code.

Explore C Standard Library Headers

Continue with locale.h or browse the library index.

Standard Library Index →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful