The only reason to use uint8_t
rather than unsigned char
(aside from aesthetic preference) is if you want to document that your program requires char
to be exactly 8 bits. uint8_t
exists if and only if CHAR_BIT==8
, per the requirements of the C standard.
The rest of the intX_t
and uintX_t
types are useful in the following situations:
- reading/writing disk/network (but then you also have to use endian conversion functions)
- when you want unsigned wraparound behavior at an exact cutoff (but this can be done more portably with the
&
operator).
- when you're controlling the exact layout of a struct because you need to ensure no padding exists (e.g. for
memcmp
or hashing purposes).
On the other hand, the uint_least8_t
, etc. types are useful anywhere that you want to avoid using wastefully large or slow types but need to ensure that you can store values of a certain magnitude. For example, while long long
is at least 64 bits, it might be 128-bit on some machines, and using it when what you need is just a type that can store 64 bit numbers would be very wasteful on such machines. int_least64_t
solves the problem.
I would avoid using the [u]int_fastX_t
types entirely since they've sometimes changed on a given machine (breaking the ABI) and since the definitions are usually wrong. For instance, on x86_64, the 64-bit integer type is considered the "fast" one for 16-, 32-, and 64-bit values, but while addition, subtraction, and multiplication are exactly the same speed whether you use 32-bit or 64-bit values, division is almost surely slower with larger-than-necessary types, and even if they were the same speed, you're using twice the memory for no benefit.
Finally, note that the arguments some answers have made about the inefficiency of using int32_t
for a counter when it's not the native integer size are technically mostly correct, but it's irrelevant to correct code. Unless you're counting some small number of things where the maximum count is under your control, or some external (not in your program's memory) thing where the count might be astronomical, the correct type for a count is almost always size_t
. This is why all the standard C functions use size_t
for counts. Don't consider using anything else unless you have a very good reason.