CInteger Types

Integer Types

C offers several flavors of integer type — short, int, long, and long long — each intended to give the programmer some control over the range of values a variable can hold and how much memory it consumes. Each of these can also be marked signed or unsigned.

The integer family

Type

Minimum guaranteed width

Typical width (most 64-bit platforms)

short / short int

16 bits

16 bits

int

16 bits

32 bits

long / long int

32 bits

32 or 64 bits (platform-dependent!)

long long (C99+)

64 bits

64 bits

C
#include <stdio.h>

int main(void) {
    short     s = 100;
    int       i = 100000;
    long      l = 1000000000L;
    long long ll = 9000000000000000000LL;

    printf("sizeof(short)=%zu sizeof(int)=%zu sizeof(long)=%zu sizeof(long long)=%zu\n",
           sizeof(short), sizeof(int), sizeof(long), sizeof(long long));
    return 0;
}
sizeof(short)=2 sizeof(int)=4 sizeof(long)=8 sizeof(long long)=8
Signed vs unsigned, recap

By default, integer types are signed, meaning they can represent both negative and positive values. Adding the unsigned keyword tells the compiler to use the same number of bits to represent only non-negative values, doubling the maximum positive value it can hold. The Signed & Unsigned page covers this distinction, and the undefined-behavior pitfalls around it, in much greater depth.

C
int a = -5;            /* signed: negative values allowed */
unsigned int b = 5u;   /* unsigned: only non-negative values */
The standard only guarantees minimums
int is not guaranteed to be 32 bits
The C standard specifies only the minimum range each integer type must be able to represent — it deliberately does not fix an exact bit width. On the vast majority of modern desktop and server compilers `int` happens to be 32 bits, but the standard allows a conforming compiler to make `int` 16 bits (common on some embedded platforms) or something else entirely. Writing code that silently assumes "`int` is always 4 bytes" is a real, recurring source of portability bugs when that code is later compiled for a different platform. Never hard-code an assumed size — use `sizeof` to check at compile/run time, or use the fixed-width types below when an exact size genuinely matters.
Fixed-width types: <stdint.h>

When you need a guaranteed, exact bit width — for a binary file format, a network protocol, or bit-level hardware register access — the modern, portable answer is the <stdint.h> header (introduced in C99). It defines exact-width integer type aliases that are guaranteed to be precisely the size their name promises, on every conforming platform.

Type

Guaranteed size

Range (signed) / (unsigned)

int8_t / uint8_t

8 bits

-128 to 127 / 0 to 255

int16_t / uint16_t

16 bits

-32,768 to 32,767 / 0 to 65,535

int32_t / uint32_t

32 bits

~-2.1B to 2.1B / 0 to ~4.3B

int64_t / uint64_t

64 bits

very large ranges, see <stdint.h>

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

int main(void) {
    int32_t  temperature = -15;   /* exactly 32 bits, everywhere */
    uint64_t big_counter = 18000000000ULL; /* exactly 64 bits, everywhere */

    printf("temperature=%d big_counter=%llu\n",
           temperature, (unsigned long long)big_counter);
    return 0;
}
When to reach for stdint.h
Use plain `int` for everyday loop counters and general arithmetic — it's the type C's own operators naturally promote to. Reach for `int32_t`, `uint16_t`, and friends specifically when the exact number of bits matters: serialization formats, hardware registers, cryptography, or any code that must behave identically on a 16-bit microcontroller and a 64-bit server.
  • The integer family, from smallest to largest guaranteed range, is: short, int, long, long long.

  • The C standard guarantees only minimum widths — never assume int is exactly 32 bits.

  • Use sizeof(type) to check the actual size on your platform.

  • Use <stdint.h> types (int32_t, uint64_t, etc.) when an exact width is required for portability.