开发者

Why, if a char is initialized to 1 and then left shifted 7 times and the value printed using %d, does it show -128?

I am aware of the 2s complement representation of signed values. But how does binary '10000000' become -128 in decimal(using %d).

for +64 binary rep = '01000000' for -64 binary rep = '11000000' which is 2's complement of '01000000'

can some one please explain?

Program:

int main()
{
   char ch = 1;
   int count = 0;
   while(count != 8)
   {
     printf("Before shift val of ch = %d,count=%d\n",ch,count);
     ch = ch << 1;     

     printf("After  shift val of ch = %d,count=%d\n",ch,count);
     //printBinPattern(ch);  
     printf("*************************************\n");
     count++;
   }
   return 0;
}

Output:

Before shift val of ch = 1, count=0
After  shift val of ch = 2, count=0
*************************************
...
... /* Output not shown */
Before shift val of ch = 32, count=5
After  shift val of ch = 64, count=5
*************************************
Before shift val of ch = 64, count=6
After  shift val of ch = -128, count=6
*************************************
Before shift val of **ch = -128**, count=7
After  shift val of ch = 0, count=7
*************************************
Before shift val 开发者_开发技巧of ch = 0, count=8
After  shift val of ch = 0, count=8
*************************************


Because on your compiler, char means signed char.

Char is just a tiny integer, generally in the range of 0...255 (for unsigned char) or -128...127 (for signed char).

The means of converting a number to 2-complement negative is to "invert the bits and add 1"

128 = "1000 0000". Inverting the bits is "0111 1111". Adding 1 yields: "1000 0000"


I am aware of the 2s complement representation of signed values.

Well, obviously you aren't. A 1 followed by all 0s is always the smallest negative number.


The answer is implementation defined as the type of 'default char' is implementation defined.

$3.9.1/1

Objects declared as characters (char) shall be large enough to store any member of the implementation’s basic character set. If a character from this set is stored in a character object, the integral value of that character object is equal to the value of the single character literal form of that character. It is implementationdefined whether a char object can hold negative values. Characters can be explicitly declared unsigned or signed. Plain char, signed char, and unsigned char are three distinct types.

$5.8/1 -

"The operands shall be of integral or enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand."

So when the value of char becomes negative, left shift from thereon has undefined behavior.


That's how it works.

-1 = 1111 1111
-2 = 1111 1110
-3 = 1111 1101
-4 = 1111 1110
...
-126 = 1000 0010
-127 = 1000 0001
-128 = 1000 0000


Two's complement is exactly like unsigned binary representation with one slight change:

The MSB (bit n-1) is redefined to have a value of -2n-1 instead of 2n-1.

That's why the addition logic is unchanged: because all the other bits still have the same place value.

This also explains the underflow/overflow detection method, which involves checking the carry from bit (n-2) into bit (n-1).


There is a pretty simple process for converting from a negative two's complement integer value to it's positive equivalent.

0000 0001 ; The x = 1
1000 0000 ; x <<= 7

The two's complement process is two-steps... first, if the high-bit is 1, reverse all bits

0111 1111 ; (-) 127

then add 1

1000 0000 ; (-) 128


Supplying a char to a %d format specifier that expects an int is probably unwise.

Whether an unadorned char is signed or unsigned is implementation defined. In this case not only is it apparently signed, but also the char argument has been pushed on to the stack an an int sized object and sign extended so that the higher order bits are all set to the same value as the high order bit of the original char.

I am not sure whether this is defined behaviour or not without looking it up, but personally I'd have cast the char to an int when formatting it with %d. Not least because some compilers and static analysis tools will trap that error and issue a warning. GCC will do so when -Wformat is used for example.

That is the explanation, if you want a solution (i.e. one that prints 128 rather than -128) then you need to cast to unsigned and mask-off the sign extension bits as well as using a correctly matching format specifier:

printf("%u", (unsigned)ch & 0xff );
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜