As I understand it, the C specification says that type int is supposed to be the most efficient type on target platform that contains at least 16 bits.
I
On some platforms, using 16-bit values may be much slower than using 32-bit values [e.g. an 8-bit or 16-bit store would require performing a 32-bit load, modifying the loaded value, and writing back the result]. Even if one could fit twice as many 16-bit values in a cache as 32-bit values (the normal situation where 16-bit values would be faster than 32-bit values on 32-bit systems), the need to have every write preceded by a read would negate any speed advantage that could produce unless a data structure was read far more often than it was written. On such platforms, a type like int_fast16_t would likely be 32 bits.
That having been said, the Standard does not unfortunately allow what would be the most helpful semantics for a compiler, which would be to allow variables of type int_fast16_t whose address is not taken to arbitrarily behave as 16-bit types or larger types, depending upon what is convenient. Consider, for example, the method:
int32_t blah(int32_t x)
{
int_fast16_t y = x;
return y;
}
On many platforms, 16-bit integers stored in memory can often be manipulated just as those stored in registers, but there are no instructions to perform 16-bit operations on registers. If an int_fast16_t variable stored in memory are only capable of holding -32768 to +32767, that same restriction would apply to int_fast16_t variables stored in registers. Since coercing oversized values into signed integer types too small to hold them is implementation-defined behavior, that would compel the above code to add instructions to sign-extend the lower 16 bits of x before returning it; if the Standard allowed for such a type, a flexible "at least 16 bits, but more if convenient" type could eliminate the need for such instructions.