CType Sizes & limits.h

Type Sizes & limits.h

Because C only guarantees minimum sizes for its built-in types, any code that cares about exact ranges or byte counts needs a reliable way to check them on the platform it is actually compiled for, rather than assuming a fixed size. C gives you two tools for this: the sizeof operator, and the constants defined in <limits.h> and <float.h>.

sizeof — checking actual sizes

sizeof is a compile-time operator that returns the size, in bytes, of a type or expression, as an unsigned value of type size_t. It works on both fundamental types and your own structs and arrays.

C
#include <stdio.h>

int main(void) {
    printf("sizeof(char)      = %zu\n", sizeof(char));
    printf("sizeof(short)     = %zu\n", sizeof(short));
    printf("sizeof(int)       = %zu\n", sizeof(int));
    printf("sizeof(long)      = %zu\n", sizeof(long));
    printf("sizeof(long long) = %zu\n", sizeof(long long));
    printf("sizeof(float)     = %zu\n", sizeof(float));
    printf("sizeof(double)    = %zu\n", sizeof(double));
    return 0;
}
sizeof(char)      = 1
sizeof(short)     = 2
sizeof(int)       = 4
sizeof(long)      = 8
sizeof(long long) = 8
sizeof(float)     = 4
sizeof(double)    = 8
Use %zu for size_t
`sizeof` returns a `size_t`, an unsigned type whose own width varies by platform. The correct, portable `printf` conversion for it is `%zu` (added in C99) — using `%d` technically invokes undefined behavior on platforms where `size_t` is wider than `int`.
<limits.h> — integer range constants

Rather than hard-coding what you assume the min/max of a type to be, <limits.h> provides named constants that the compiler fills in correctly for its own platform, giving you portable range checks.

Constant

Meaning

CHAR_BIT

Number of bits in a byte (almost always 8)

INT_MIN, INT_MAX

Minimum and maximum value of int

UINT_MAX

Maximum value of unsigned int

LONG_MIN, LONG_MAX

Minimum and maximum value of long

LLONG_MIN, LLONG_MAX

Minimum and maximum value of long long

SCHAR_MIN, SCHAR_MAX, UCHAR_MAX

Range of signed char / unsigned char

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

int main(void) {
    printf("CHAR_BIT = %d\n", CHAR_BIT);
    printf("INT_MIN  = %d\n", INT_MIN);
    printf("INT_MAX  = %d\n", INT_MAX);
    printf("LONG_MAX = %ld\n", LONG_MAX);
    return 0;
}
CHAR_BIT = 8
INT_MIN  = -2147483648
INT_MAX  = 2147483647
LONG_MAX = 9223372036854775807
<float.h> — floating-point limits

The floating-point equivalent of <limits.h> is <float.h>, which exposes constants describing the precision and range of float, double, and long double on the current platform, such as FLT_MAX, DBL_MAX, FLT_EPSILON, and DBL_DIG (the number of reliably representable decimal digits).

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

int main(void) {
    printf("FLT_MAX     = %e\n", FLT_MAX);
    printf("DBL_MAX     = %e\n", DBL_MAX);
    printf("FLT_EPSILON = %e\n", FLT_EPSILON);
    return 0;
}
Don't hard-code assumed sizes
A real portability bug: assuming int is always 4 bytes
Code that hard-codes assumptions like "an int is 4 bytes" or "a pointer fits in an int" works fine on today's common desktop platforms — until it's compiled for a 16-bit microcontroller, an unusual embedded target, or a platform with a different pointer width, where those assumptions quietly break. Serializing a struct to a file using a hard-coded byte offset, packing values into a fixed-size buffer computed by hand, or casting a pointer to `int` instead of `intptr_t`, are all real bugs that show up this way. Always compute sizes with `sizeof`, use `<stdint.h>` types when an exact width matters, and check `<limits.h>` rather than hard-coding numeric ranges.
  • Use sizeof(type) to find the actual size of a type on the current platform at compile time.

  • %zu is the correct printf conversion for the size_t value sizeof returns.

  • <limits.h> provides portable integer range constants like INT_MAX and CHAR_BIT.

  • <float.h> provides the floating-point equivalents, like FLT_MAX and DBL_EPSILON.

  • Never hard-code an assumed type size — it is a classic source of portability bugs.