uint_least8_t is the smallest type that has at least 8 bits.
uint_fast8_t is the fastest type that has at least 8 bits.
You can see the differences by imagining exotic architectures. Imagine a 20-bit architecture. Its unsigned int has 20 bits (one register), and its unsigned char has 10 bits. So sizeof(int) == 2, but using char types requires extra instructions to cut the registers in half. Then:
uint8_t: is undefined (no 8 bit type).uint_least8_t: isunsigned char, the smallest type that is at least 8 bits.uint_fast8_t: isunsigned int, because in my imaginary architecture, a half-register variable is slower than a full-register one.