The difference of int8_t, int_least8_t and int_fast8_t?

The difference is defined in the sections of the C99 standard that Carl Norum quoted. But it may be useful to have an example.

Suppose you have a C compiler for a 36-bit system, with char = 9 bits, short = 18 bits, int = 36 bits, and long = 72 bits. Then

  • int8_t does not exist, because there is no way to satisfy the constraint of having exactly 8 value bits with no padding.
  • int_least8_t is a typedef of char. NOT of short or int, because the standard requires the smallest type with at least 8 bits.
  • int_fast8_t can be anything. It's likely to be a typedef of int if the "native" size is considered to be "fast".

From the spec section 7.8.1.1 Exact-width integer types, paragraph 1:

The typedef name intN_t designates a signed integer type with width N , no padding bits, and a two’s complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits.

And from: 7.18.1.2 Minimum-width integer types, paragraph 1:

The typedef name int_leastN_t designates a signed integer type with a width of at least N, such that no signed integer type with lesser size has at least the specified width. Thus, int_least32_t denotes a signed integer type with a width of at least 32 bits.

And finally from 7.18.1.3 Fastest minimum-width integer types, paragraph 2:

The typedef name int_fastN_t designates the fastest signed integer type with a width of at least N. The typedef name uint_fastN_t designates the fastest unsigned integer type with a width of at least N.


Here's a conceptually simple answer: the width of int*N_t for all three types must be >= N. intN_t has exactly N bits, int_leastN_t is the least (narrowest) such type, and int_fastN_t is the fastest such type.

For example, on a machine with 8 bit bytes and 32 bit fast registers, int8_t and int_least8_t are aliased to signed char but int_fast8_t is aliased to int32_t. Whereas, if the implementation chose to define them, int_least24_t and int_fast24_t would both be aliased to int32_t, with int24_t left undefined.

Edit: as Technophile points out below, the real issue for fast types is memory, not registers (generally, operations on the low-order bits of registers can be done just as fast as on the whole register). For example, writing to an int8_t in memory may require loading the 32-bit word containing it, modifying just the byte, and then writing it back, whereas if it were stored in a 32-word it could be written without reading.