The same sequence of bits can have radically different meanings based on context.
Integer types have a fixed number of bits - the C language definition mandates that the signed int
type must be able to represent at least the range [-32,767...32,767]
, meaning an int
must be at least 16 bits wide1.
There are several different ways to represent signed integers. The most common is 2's complement, but some architectures may use 1's complement or sign-magnitude.
To flip the sign on a 2's complement number, do a bitwise negation and add 1 (this example assumes 8 bit integers):
00001101 == 13
11110010 + 1 == 11110011 == -13
11110011 == -13
00001100 + 1 == 00001101 == 13
One of the chief advantages of 2's complement is that you have a single representation for 0, and it gives you a slightly wider range of values - [-2n-1..2n-1-1]
To flip the sign on a 1's complement number, you simply do a bitwise negation:
00001101 == 13
11110010 == -13
11110010 == -13
00001101 == 13
With 1's complement, you have positive and negative representations for 0 - 00000000
and 11111111
- and the range is [-2n-1-1..2n-1-1]
With sign-magnitude, you leave the value bits as-is and flip the sign bit:
00001101 == 13
10001101 == -13
Like 1's complement, you get two encodings for positive and negative 0 - 00000000
and 10000000
.
Unsigned integer types have the same width as their signed counterparts, and their range is [0..2n-1]
.
So, the bit sequence 11110011
can mean -13 in 2's complement, -12 in 1's complement, -115 in sign-magnitude, or 243 unsigned.
- Note that some architectures may use padding bits, such that it takes more than 16 bits to represent 32,767.