1

I'm confused about the negation operation after doing the bit shift. For example:

-(1<<7) is 0xffffff80 

But why are the most significant bits filled with 1? I'm confused about what the operation - means here.

Edit 1: I used printf("%#08x\n", -(1<<7)) to print out the value.

5
  • 7
    Because your platform uses a 2's complement representation for negative numbers... Commented Aug 22, 2013 at 17:15
  • 1
    Wikipedia link to two's complement. Commented Aug 22, 2013 at 17:15
  • This is not just about 2's complement. Sign bits and rotations also need to be discussed to answer this question. Commented Aug 22, 2013 at 20:18
  • @JackCColeman: But it is about 2's complement. Sign bits are all about 2's complement, and there's no rotations going on here... Commented Aug 23, 2013 at 1:31
  • @Cornstalks, sorry shift left, NOT rotations. Commented Aug 23, 2013 at 1:49

5 Answers 5

2

First of all, thank-you for this question. It is usually a good idea to code a test program to illustrate something you are not sure about and then try different things to figure out the details.

Comments, like that is UB, are usually not accurate. In this case what happens is very predictable and reasonable and is exactly what an experienced programmer should expect.

I ran the following code on Eclipse/Microsoft C compiler:

#include <stdio.h> main() { int i; unsigned int j; i = -(1<<7); printf("%i\n", i); printf("%08x\n", i); j = -(1<<7); printf("%u\n", j); printf("%08x\n", j); } 

And got the following output:

-128 ffffff80 4294967168 ffffff80 

These are expected, because: (1 << 7) equals 128 and -(128) is -128. The printf of the contents of i produced exactly the value of -128 in binary form.

The way to see this is to take the 2's complement of ffffff80 = 0000007f + 1 = 00000080 which is 128 in binary. Thus, you can see that taking the 2's complement of a number is how we take the negative of an integer.

The really big number is the unsigned value of the same contents.

Whenever possible write-up a little bit of code to examine how stuff works!

Sign up to request clarification or add additional context in comments.

2 Comments

I'm guessing UB stands for undefined behaviour.
Thank you very much, Jack. I did write a program in Linux 64bits, and used printf(%08x). It's the same result with yours. print it out as an unsigned value is really helpful to understand. :)
0

The minus operator (is implementation defined but most likely to) is going to perform a two's complement on its argument (128 decimal in this case). 2's complement is: subtract 1 and invert all the bits.

Comments

0

The significant bits are filled with 1 because they represent the sign and repeating them won't affect the value. For a positive number, 10 and 010 and 0000010 are all equal. And since a most significant bit of 1 represents negative, putting as many 1s as much as you want in front of a negative number don't affect the magnitude. You can check this fact using 2s complement arithmetic.

1 Comment

"For these numbers putting as much as any 1s don't affect the magnitude" You're going to have to clarify what you mean there.
0

-(1<<7) is not 0xffffff80. 1<<7 is 1 times 2 to the 7th power, i.e. 128. So -(1<<7) is -128. The most likely explanation for why you're seeing it as 0xffffff80 is that you're invoking undefined behavior by passing it to printf for use with the %x format specifier. %x takes an unsigned int argument (and can also take a signed int as long as the value is non-negative) but the argument you're passing has type int and is negative. Therefore, undefined behavior results.

6 Comments

are you sure printf( "%x", -(1<<7) ) really is UB (which means 'dragons might fly out your nose') or just platform/implementation dependant?
Yes, it's UB. See C11 7.21.6.1 The fprintf function, paragraph 9: "If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined."
And just above under paragraph 8: "o,u,x,X The unsigned int argument is converted to unsigned octal (o), unsigned decimal (u), or unsigned hexadecimal notation (x or X)" (emphasis mine).
@IngoLeonhardt UB is not really that. It is "constrained by imagination and skill of the compiler developers, tolerance of the compiler distributor for funny things happening to their clients, as well as current natural laws governing the computer where program is run". I'm pretty sure that all of these disallow nose dragons.
No, it's not. The value of -128 is -128. Period. The representation of -128 may or may not be the same as the representation of 0xffffff80u, depending on several factors, but C expressions are based on values, not representations.
|
0

The answer is very simple and results from the way how negavie numbers are save in computer's memory.

I guess it is obvious for you what 1 << 7 means. It equals to 128. Your "-" sign just means you want to change te sign of the result so the final result is -128.

But why did you get someting different? Here is the answer:

Generally there a two types of variables: signed and unsigned. Both types are saved in momory which actually doesn't know which type is begin used. It is just up to programmer to know what kind of number is stored.

When you declare a variable as unsigned, it can store values from 0 to n, where n is the maximum value for a certain type of variable.

When you use signed one, you can store there a value from defined negative value, up to some defined positive value.

When unsigned variable is used, it is very simple to calculate is value. Please consider a simple example of 8 bit (1 byte) unsigned variable:

the minimum value is 0 as I said before, and the maximum is 255 when all of 8 bits are set.

For the signed type of variable a special format is being used: numbers from 0 to 127 are being saved the same way as for unsigned type. And the value of 127 is the maximum for a 8 bit variable. The minimum value is -128 and is stored as 0b10000000 or 0x80. Next one is -127 and is saved as 0b10000001 or 0x81 and so on. The biggest, negative number is -1 and is saved as 0b11111111 or 0xFF.

So if you have a byte value 0xff it can be both: 255 (when unsigned) or -1 (when signed). The notation used here for signed types of variables is called U2 - please read about this.

In your particular case it looks like you have a signed (-128) value which was read as unsigned one. In your case a 32 bit (4 bytes) variable (probably (unsigned) int) was used so it looks a little bit different (the result is longer), but you may see some similarity: the last two digits for -128 in U2 system will always be 0x80 no matter how many bits are being used to store the value.

1 Comment

Thank you very much! I think printf(%#) prints out the bits how the value -128 is stored in the machine. That's why I saw the 0xFF. :-)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.