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.

Tushar Gupta - curioustushar
  • 58,085
  • 24
  • 103
  • 107
Mike
  • 1,841
  • 2
  • 18
  • 34

5 Answers5

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!

JackCColeman
  • 3,777
  • 1
  • 15
  • 21
  • I'm guessing UB stands for undefined behaviour. – Andrew Morton Aug 22 '13 at 18:38
  • 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. :) – Mike Aug 23 '13 at 01:13
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.

Bart
  • 19,692
  • 7
  • 68
  • 77
Paul Evans
  • 27,315
  • 3
  • 37
  • 54
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.

Andromeda
  • 1,370
  • 2
  • 10
  • 15
  • "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. – Dennis Meng Aug 22 '13 at 17:22
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.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • are you sure `printf( "%x", -(1<<7) )` really is UB (which means 'dragons might fly out your nose') or just platform/implementation dependant? – Ingo Leonhardt Aug 22 '13 at 17:41
  • 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." – R.. GitHub STOP HELPING ICE Aug 22 '13 at 17:47
  • 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). – R.. GitHub STOP HELPING ICE Aug 22 '13 at 17:48
  • 2
    @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. – hyde Aug 22 '13 at 18:04
  • The value of -128 is 0xffffff80. – JackCColeman Aug 22 '13 at 18:31
  • 1
    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. – R.. GitHub STOP HELPING ICE Aug 22 '13 at 18:44
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.

Michał Walenciak
  • 4,257
  • 4
  • 33
  • 61
  • 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. :-) – Mike Aug 23 '13 at 01:09