2

I have the following piece of code,

if (index > ((v.size() >> 1) - 1)) { }

v.size() is 0 and index is 1. The execution does not get into the if block. But if I change the above code to,

int limit = (v.size() >> 1) - 1;
if (index > limit) { }

and with the same values of v.size() and index, the execution does get into the if block.

Why does this behavior happen? Thanks.

Rajkumar P
  • 49
  • 1
  • 4
  • 3
    Probably because `v.size()` is not an `int`. But we don't know what it does because the relevant context is missing from your code. – melpomene Aug 26 '17 at 07:52
  • 1
    Ah, ignored warnings... – Retired Ninja Aug 26 '17 at 07:53
  • It's due to implicit conversion to an unsigned type. The second method is effectively a cast. Nice question: I don't understand the downvote. – Bathsheba Aug 26 '17 at 07:59
  • 1
    @Bathsheba This question does not show any research effort, and it's unclear because all the important parts (the types of `index` and `v.size()`) are missing. – melpomene Aug 26 '17 at 08:01
  • To a freshman this behaviour is so peculiar it would be difficult to know how to embark on this research. If the OP suspected it was down to types then this post would be almost rhetorical - although there is nothing wrong with that per se. I'm pretty sure many of my best answers are those to rhetorical questions. – Bathsheba Aug 26 '17 at 08:02
  • Change it to `index >= v.size()` and avoid the whole problem. – user207421 Aug 26 '17 at 10:33
  • This isn't the problem, but you don't need the parentheses around `(v.size() >> 1) - 1`. They make the code **very** hard to read. – Pete Becker Aug 26 '17 at 12:50

1 Answers1

0

You are obviously performing unsigned comparison. The return type of v.size() is likely size_t, which is an unsigned integer. Thus, the expression (v.size() >> 1) - 1 yields the largest possible unsigned integer. Unless you convert that back to a signed integer type, you won't get positive comparison results.

A simple cast to ssize_t before the subtraction will fix your problem:

if (index > (((ssize_t)v.size() >> 1) - 1)) { }

I have used ssize_t because that type is guaranteed to be able to hold any size_t value, reinterpreting it to negative if its most significant bit is set. That cannot be said for int, as that is usually only 32 bits on 64 bit platforms. So, using int as you did in your second example, may cut off some bits.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • I can't believe people still get this wrong, you have to cast to a signed type *before* subtracting! Casting *after* unsigned overflow (which is fine and well defined) is too late, you get signed overflow, which is undefined behavior (wraparound is *not* guaranteed, and compilers exploit this undefined behavior even on platforms where two's complement wraparound would be natural). Just cast the result of `size()` to a signed type and perform arithmetic on it. – Matteo Italia Aug 26 '17 at 08:42
  • @MatteoItalia Afaik, `(int)(unsigned)i == i` is well defined by the newer standards. Could you please give a standard reference for your claim? – cmaster - reinstate monica Aug 26 '17 at 08:44
  • even if it's is (standard reference?), it is not our case - you are not doing a roundtrip from/to a signed value passing through an unsigned value, you are calculating an unsigned value that overflows and then casting it to a signed value. This is not guaranteed to yield anything useful (and for example it obviously couldn't work correctly on platforms with e.g. sign and magnitude or one's complement representation for integers). – Matteo Italia Aug 26 '17 at 08:48
  • @MatteoItalia Well, if you think so - I've taken that offending cast out. – cmaster - reinstate monica Aug 26 '17 at 08:52
  • [Even roundtrip doesn't seem to be allowed, as I remembered](https://stackoverflow.com/questions/22623453/c-converting-unsigned-to-signed-integer-portability). I'd upvote this if you fixed the sentence where you talk about "converting back" to signed value - you cannot really convert it back in a simple way without possibly overflowing. – Matteo Italia Aug 26 '17 at 09:02