Every modern programming language I've encountered has well-defined data types. Java, for example, has an int that is exactly 32 bits and a long that is exactly 64 bits. This is not implementation specific but built into the spec itself. C, on the other hand, has a short that is at least 16 bits, an int that is at least 16 bits, and a long that is at least 32 bits. Because it is defined as at least, though, they can be much larger, which results in serious portability issues.
I have never understood this. I have always chalked it up to being the result of differing hardware standards in the 1970's, but this doesn't actually make sense to me. Even if there were a lot of computers that couldn't handle 64 bit data types, that still doesn't excuse not defining a short as necessarily 16 bits and an int as necessarily 32 bits. From the standards we already see 32 bits as a minimum requirement for any hardware.
This proliferation of standards has resulted in advice like the following, taken from the article How to C (as of 2016):
If you find yourself typing
charorintorshortorlongorunsignedinto new code, you’re doing it wrong.For modern programs, you should
#include <stdint.h>then use standard types.For more details, see the
stdint.hspecification.The common standard types are:
int8_t,int16_t,int32_t,int64_t— signed integersuint8_t,uint16_t,uint32_t,uint64_t— unsigned integersfloat— standard 32-bit floating pointdouble- standard 64-bit floating pointNotice we don’t have
charanymore. char is actually misnamed and misused in C.Developers routinely abuse
charto mean “byte” even when they are doing unsignedbytemanipulations. It’s much cleaner to useuint8_tto mean single a unsigned-byte/octet-value anduint8_t *to mean sequence-of-unsigned-byte/octet-values.
I've also noticed quite a bit of advice recommending the use of size_t as the standard go to int replacement, as in Modern C by Jens Gustedt which uses a size_t as the control variable in a for loop in the very first example of the book.