tags:

views:

214

answers:

7

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
*************************************
+14  A: 

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"

James Curran
The general range for `signed char` is [ -128, **127** ]. The 'minimal' range is [ -127, 127 ].
schot
What happens to the carry over genarated when "0111 1111" + 1 is done ? This is what is confusing me.
Abhijeet
"0111 1111" + 1 = "1000 0000", the carry goes to the MSB. Now, 127 + 1 = -128 due to wrapping, but that happens with all signed integer types.
James Curran
`127 + 1` can actually give anything at all, or crash the process. Signed integer overflow is not well defined.
caf
+2  A: 

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.

Chubsdad
+13  A: 

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.

FredOverflow
+1  A: 

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
Jonatan
shouldn't -128 be equal to "11000 0000"
Abhijeet
@Abhijeet: If you've got 9 bit bytes available, it would be. That's a bit uncommon though.
Donal Fellows
A: 

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).

Ben Voigt
A: 

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
jkerian
A: 

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 );
Clifford
See 6.5.2.2 para 6 regarding default argument promotions -- behaviour of calling `...` functions is indeed undefined. Quite how you're supposed to use this feature for something useful is anybody's guess.Fortunately behaviour on every compiler I have used (a fair number, though not all of them) is to promote integral types to at least int, and floats to double, as per what seems to be the defined behaviour for functions without a prototype. The standard is a bit unclear on the whole subject though.
brone
You need to cast to `unsigned char` before performing the bitwise and, or the behavior is implementation-defined.
R..
@R: Depending on the signed'ness of `char`, it will implicitly convert to `int` as either `0xffffff80` or just `0x00000080`. When masked with `0xff` the result will be correct in both cases. However, the parentheses were in fact unnecessary, and removing them avoids the issue altogether I think.
Clifford