2

I'm seeing strange behavior when I try to apply a right bit-shift within a variable declaration/assignment:

unsigned int i = ~0 >> 1;

The result I'm getting is 0xffffffff, as if the >> 1 simply wasn't there. It seems to be something about the ~0, because if I instead do:

unsigned int i = 0xffffffff >> 1;

I get 0x7fffffff as expected. I thought I might be tripping over an operator precedence issue, so tried:

unsigned int i = (~0) >> 1;

but it made no difference. I could just perform the shift in a separate statement, like

unsigned int i = ~0;
i >>= 1;

but I'd like to know what's going on.

update Thanks merlin2011 for pointing me towards an answer. Turns out it was performing an arithmetic shift because it was interpreting ~0 as a signed (negative) value. The simplest fix seems to be:

unsigned int i = ~0u >> 1;

Now I'm wondering why 0xffffffff wasn't also interpreted as a signed value.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
ivan
  • 6,032
  • 9
  • 42
  • 65
  • 1
    Take a look at [this question](http://stackoverflow.com/a/7632/391161). – merlin2011 Jan 19 '16 at 04:10
  • @merlin2011 Ah, this answer lower down on that page has the cause: http://stackoverflow.com/a/10101/1631106 – ivan Jan 19 '16 at 04:17
  • your first mistake is assuming that `~0` means `0xffffffff` – M.M Jan 19 '16 at 04:18
  • @M.M I wouldn't call it an assumption. I tested it out on my machine to see if that was the case. – ivan Jan 19 '16 at 04:21
  • 1
    @ivan it is quite strange behavior to see the result in your machine. Things are going well on mine. Is your machine 32-bit or 64-bit? – Ian Jan 19 '16 at 04:25
  • @Ian It's 32-bit. os x macbook air from 2013/14 – ivan Jan 19 '16 at 04:27
  • @ivan mine is 64-bit. I cannot really test here, but just to be safe, how about putting `0ul` instead of `0u`? Is the result the same? – Ian Jan 19 '16 at 04:28
  • @ivan according to this: http://en.cppreference.com/w/c/language/operator_precedence the (type) cast and the `~` is of the same precedence. Just to be very sure, you could also put bracket on your casting. – Ian Jan 19 '16 at 04:32
  • @Ian I tried `0ul` and it generates a compiler warning: `implicit conversion from 'unsigned long' to 'unsigned int' changes value from 9223372036854775807 to 4294967295`. The output I then get is `0xffffffff` – ivan Jan 19 '16 at 04:34
  • @ivan and what happen if you put bracket? `~(0u)` because everything is ok in my computer, whether I put `u` or `ul`, with or without bracket. Any optimizer you use in your IDE? I use `CodeBlocks` – Ian Jan 19 '16 at 04:35
  • @Ian If I use `~(0u)` it works, just as `~0u` did. I'm not using an ide. Just vim and gcc in the terminal. – ivan Jan 19 '16 at 04:39
  • @ivan the fact that `~0 >> 1` and `0xffffffff >> 1` give different results proves that `~0` and `0xffffffff` are different – M.M Jan 19 '16 at 04:47
  • @M.M It seems like `0xffffffff` is unsigned, but can you explain or point me toward some relevant documentation? – ivan Jan 19 '16 at 04:50
  • 1
    @ivan see the answers to [this question](http://stackoverflow.com/questions/24666567/why-does-1-1-and-0xffffffff-1-produce-different-results) – M.M Jan 19 '16 at 04:52
  • 1
    @M.M Ah, I think I see what you're getting at now. Though `~0` and `0xffffffff` have the same underlying bit representation, `~0` is the one's compliment of a signed int 0 (so -1), while `0xffffffff` is a positive integer too large to store in a signed int (on my machine, at least), and thus unsigned. I hope I got that right. Thanks :) – ivan Jan 19 '16 at 05:06
  • Also note that right shifting negative signed values is implementation defined: `-1 >> 1` could print as `7fffffff` as well on a different environment. – chqrlie Jan 19 '16 at 05:15

2 Answers2

1

It is how c compiler works for signed value. The base literal for number in C is int (in 32-bit machine, it is 32-bit signed int)

You may want to change it to:

unsigned int i = ~(unsigned int)0 >> 1;

The reason is because for the signed value, the compiler would treat the operator >> as an arithmetic shift (or signed shift).

Or, more shortly (pointed out by M.M),

unsigned int i = ~0u >> 1;

Test:

printf("%x", i);

Result:

enter image description here

Community
  • 1
  • 1
Ian
  • 30,182
  • 19
  • 69
  • 107
0

In unsigned int i = ~0;, ~0 is seen as a signed integer (the compiler should warn about that).

Try this instead:

unsigned int i = (unsigned int)~0 >> 1;
Danny_ds
  • 11,201
  • 1
  • 24
  • 46