N bits can represent 2N different values:
1 bit, 2 values - 0, 1
2 bits, 4 values - 00, 01, 10, 11
3 bits, 8 values - 000, 001, 010, 011, 100, 101, 110, 111
etc.
A type that's 8 bits wide can represent 28, or 256 different values. A type that's 16 bits wide1 can represent 216, or 65536 different values.
The same bit patterns can be interpreted different ways. There are several different ways to represent signed integer values - two's complement, ones' complement, and sign-magnitude are the three you're most likely to hear about, and two's complement is by far the most common. Here's a 4-bit example showing how bits are interpreted in each scheme:
Bits Unsigned Two's Cmp Ones' Cmp Sign-mag
---- -------- --------- --------- --------
0000 0 0 0 0
0001 1 1 1 1
0010 2 2 2 2
0011 3 3 3 3
0100 4 4 4 4
0101 5 5 5 5
0110 6 6 6 6
0111 7 7 7 7
1000 8 -8 -7 -0
1001 9 -7 -6 -1
1010 10 -6 -5 -2
1011 11 -5 -4 -3
1100 12 -4 -3 -4
1101 13 -3 -2 -5
1110 14 -2 -1 -6
1111 15 -1 -0 -7
4 bits can represent 16 different values, but those values depend on how the bits are interpreted.
Thus, unsigned char
represents values in the range [0..255]
(assuming CHAR_BIT == 8
), where signed char
represents values in the range [-128..127]
(assuming CHAR_BIT == 8
and two's complement representation for signed values). It's the same number of values (256), just over different ranges.
Similarly, a 32-bit float
can represent the same number of values as a 32-bit int
(4294967296), but they are interpreted differently. The bit pattern 439d145a16
can represent either the floating point value 3.14159
or the integer value 1134367834
(assuming IEEE-754 single-precision floating point).
- C allows for the presence of padding bits that don't contribute to the value representation for types other than
unsigned char
, but you're unlikely to see anything like that on modern hardware.