1. "...but it's printing 640..." ?
Since the 8-bit binary number for 5 is 00000101, c << 7
results in a 32-bit binary number 0...(other 20 0s)...01010000000
, which is 640 in decimal.
2. "...Is it undefined behavior..." ?
No, the behavior is defined by the standard. This behavior consists of two major processes, one is Bitwise
Shift Operators, and the other is Integer Promotions.
For Bitwise Shift Operators, in C99 6.5.7 p3:
The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.
For Integer Promotions, in C99 6.3.1.1 p2:
An object or expression with an integer type whose integer conversion rank is less
than or equal to the rank of int and unsigned int.
If an int can represent all values of the original type, the value is converted to an int;
Accoding to these definitions, the result of c << 7
would eventually be an int
type number 640, whose bit pattern is 0...(other 20 0s)...01010000000
.
One workaround is doing as what @msc suggested, that is, (char) c << 7
, which has the effect that roughly described as follows:
#1: (char)c<<7
——————> 0...(other 20 0s)...01010000000
——————> (Promotion & Truncation happened)
——————> 10000000
#2: %d
——————> (Promotion & Sign Extension happened)
——————> 1...(other 20 1s)...11110000000
#3: printf
——————> 1...(other 20 1s)...11110000000 -> -128