Skip to content
C++ Better Explained
Go back
INT_MAX and INT_MIN in C++: The Maximum and Minimum int Value

INT_MAX and INT_MIN in C++

Short answer:

ValueHow to get it
Maximum int2,147,483,647INT_MAX or std::numeric_limits<int>::max()
Minimum int−2,147,483,648INT_MIN or std::numeric_limits<int>::min()

The Two Ways to Get Them

#include <iostream>
#include <climits>   // INT_MAX, INT_MIN
#include <limits>    // std::numeric_limits

int main() {
    std::cout << INT_MAX << '\n';   // 2147483647
    std::cout << INT_MIN << '\n';   // -2147483648

    std::cout << std::numeric_limits<int>::max() << '\n';   // same
    std::cout << std::numeric_limits<int>::min() << '\n';   // same
}

Both are correct. INT_MAX is shorter; numeric_limits is the C++ way and works in templates where the type is not known in advance:

template <typename T>
T largest() {
    return std::numeric_limits<T>::max();   // INT_MAX can't do this
}

Never hard-code 2147483647. It is not guaranteed by the standard — int is only required to hold at least ±32,767 — and a literal number hides its meaning from anyone reading your code.

Why the Minimum Is One Bigger

Look closely and the range is asymmetric:

INT_MIN = -2,147,483,648
INT_MAX =  2,147,483,647

A 32-bit signed int stores 2³² = 4,294,967,296 distinct values. Half are negative, and the other half must cover zero and the positives — so the positive side loses one slot to zero. This is a consequence of two’s complement representation, which is what essentially every machine uses.

It leads to a genuinely surprising result:

std::cout << -INT_MIN;      // still negative! Undefined behaviour.
std::abs(INT_MIN);          // also undefined

There is no positive int equal to -INT_MIN, so negating it overflows.

Learning C++ properly? The C++ Better Explained Ebook covers types, memory and the STL in plain English — 87 pages, just $19.

Limits for Other Integer Types

#include <climits>
#include <limits>

std::cout << SHRT_MAX  << '\n';   // 32767
std::cout << LONG_MAX  << '\n';   // platform dependent
std::cout << LLONG_MAX << '\n';   // 9223372036854775807
std::cout << UINT_MAX  << '\n';   // 4294967295

std::cout << std::numeric_limits<long long>::max() << '\n';
std::cout << std::numeric_limits<unsigned>::max()  << '\n';

Note long is 64-bit on Linux and macOS but 32-bit on Windows. If you need a guaranteed width, use the fixed-size types:

#include <cstdint>

std::int32_t a;    // exactly 32 bits everywhere
std::int64_t b;    // exactly 64 bits everywhere

What Overflow Actually Does

int big = INT_MAX;
big = big + 1;
std::cout << big;      // usually -2147483648

In practice the value wraps to INT_MIN. But this is undefined behaviour, not a defined wrap — the standard lets the compiler assume signed overflow never happens. That means optimisers can delete checks you thought were protecting you:

// The compiler may remove this entirely!
if (x + 1 < x) { /* "overflow happened" */ }

Because x + 1 < x can only be true after overflow, and overflow “cannot happen”, the branch is dead code by the compiler’s reasoning.

Checking Before You Overflow

Test with subtraction so the overflow never occurs:

bool safeAdd(int a, int b, int& result) {
    if (b > 0 && a > INT_MAX - b) return false;   // would overflow
    if (b < 0 && a < INT_MIN - b) return false;   // would underflow
    result = a + b;
    return true;
}

Or use the compiler builtins, available in GCC and Clang:

int result;
if (__builtin_add_overflow(a, b, &result)) {
    // overflow detected safely
}

Unsigned Wraps Instead

Unsigned overflow is defined — it wraps modulo 2ⁿ:

unsigned int u = 0;
u = u - 1;
std::cout << u;        // 4294967295 — defined, not UB

That is why counting down a size_t loop to below zero produces an enormous number rather than −1, a trap covered in reversing a vector and string length.

Using INT_MAX as a Sentinel

A common pattern when searching for a minimum:

int smallest = INT_MAX;
for (int v : values) {
    if (v < smallest) smallest = v;
}

It works, but std::min_element says it more clearly — see finding the max and min. And beware: if the container is empty you are left holding INT_MAX, which is rarely what you want to display.

Quick Reference

TypeMax macronumeric_limits
intINT_MAXnumeric_limits<int>::max()
int (min)INT_MINnumeric_limits<int>::min()
shortSHRT_MAXnumeric_limits<short>::max()
long longLLONG_MAXnumeric_limits<long long>::max()
unsignedUINT_MAXnumeric_limits<unsigned>::max()

Take Your C++ Further

If you want types, memory and the rest of the fundamentals explained properly, the C++ Better Explained Ebook covers them in plain English. Just $19.

👉 Get the C++ Better Explained Ebook — $19


📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Previous Post
How to Compare Floating-Point Numbers in C++ (Why == Fails)
Next Post
How to Read Multiple Inputs on One Line in C++

Keep Learning