Because the primitive data types of C come with signed and unsigned versions. From the C99 rationale, they explain the need for the inttypes/stdint
types like this, C99 rationale V5.10 7.8:
C89 specifies that the language should support four signed and unsigned integer data types,
char, short, int and long, but places very little requirement on their size other than that int and short be at least 16 bits and long be at least as long as int and not smaller than 32
bits. For 16-bit systems, most implementations assign 8, 16, 16 and 32 bits to char, short,
int, and long, respectively. For 32-bit systems, the common practice is to assign 8, 16, 32 and
32 bits to these types. This difference in int size can create some problems for users who
migrate from one system to another which assigns different sizes to integer types, because Standard C’s integer promotion rule can produce silent changes unexpectedly. The need for defining an extended integer type increased with the introduction of 64-bit systems.
The purpose of <inttypes.h>
is to provide a set of integer types whose definitions are
consistent across machines and independent of operating systems and other implementation
idiosyncrasies. It defines, via typedef, integer types of various sizes. Implementations are free to typedef them as Standard C integer types or extensions that they support. Consistent
use of this header will greatly increase the portability of a user’s program across platforms.
The intention has been that the implementation of inttypes/stdin
would be possible to perform with typedef
. Therefore there needs to be one fixed-width type corresponding to each supported primitive data type.
As for why C has signed types in the first place, that's simply because CPU:s support both signed and unsigned number arithmetic. But also since we wish to use integer types to express stored raw binary data: the type unsigned char
/uint8_t
is the C language equivalent to a byte of raw data that could contain anything. (And that's the reason character types cannot contain any trap representations etc.)
From the C99 standard itself we can find text similar to that from your book, C99 6.2.5/6:
For each of the signed integer types, there is a corresponding (but different) unsigned
integer type (designated with the keyword unsigned) that uses the same amount of
storage (including sign information) and has the same alignment requirements.