4

I have the following C++ code:

return lineNum >= startLineNum && lineNum <= startLineNum + lines.size() - 1; 

Here, lineNum is an int, startLineNum is an int, lines is a std::vector<std::string>, and lines.size() is of type size_t.

When lineNum is 2, startLineNum is 0, and lines.size() is 0, the code returns true even though false was expected. These values were the values displayed in the debugger.

Even after adding parentheses where possible:

return ((lineNum >= startLineNum) && (lineNum <= (startLineNum + lines.size() - 1))); 

the code still incorrectly returns true.

When I refactor the code into this form:

int start = startLineNum; int end = startLineNum + lines.size() - 1; return lineNum >= start && lineNum <= end; 

it now returns false as expected.

What is going on here? I have never come across this kind of strangeness before.

12
  • How do you tell the values? Are you looking at the values displayed in the debugger, or have you printed them out beforehand? Commented Jan 29, 2018 at 14:23
  • 3
    What are the types of the variables? And please create a Minimal, Complete, and Verifiable Example to show us. Commented Jan 29, 2018 at 14:24
  • 4
    Maybe you have an issue with unsigned arithmetics. lines.size() is of size_t type, what type is startLineNum ? Commented Jan 29, 2018 at 14:24
  • 1
    @marcinj Well done! That is the problem. Commented Jan 29, 2018 at 14:25
  • 1
    @KillzoneKid: Nope. Only signed types have overflow UB. Unsigned types must wrap. Commented Jan 29, 2018 at 15:13

2 Answers 2

11

lines.size() is more than likely an unsigned type. (If lines is a std::vector for example it's certainly unsigned.)

So due to the rules of argument promotion, and the fact that the terms in

startLineNum + lines.size() - 1; 

are grouped from left to right, they are all converted to unsigned types.

This means that 0 + 0 - 1 is std::numeric_limits<decltype(lines.size())>::max() - a large number indeed, and lineNum is most likely less than it.

The rule of thumb: never use a negative when working with unsigned types, unless you really know what you're doing.

In your case, restate the problem to

lineNum < startLineNum + lines.size() 
Sign up to request clarification or add additional context in comments.

Comments

1

My guess would be that

lineNum <= startLineNum + lines.size() - 1; 

is all unsigned types. linenum is 2, the other two are 0, and 0-1 in unsigned arithmetic is something VERY large (if 4 byte something above 4 billion).

Do instead

lineNum + 1 <= startLineNum + lines.size(); 

and all should be fine.

5 Comments

Or even better: lineNum < startLineNum + lines.size().
Incidentally, I think it's much more likely that startLineNum and lineNum are of type int, and the integer literal 1 is definitely type int.
True, good catch. Though slightly less instructive, some people might think it only works for -1.
My guess would be startLineNum and lineNum are of type std::size_t, and of course 1 is of type int, but that doesn't mean the difference is signed...
Still, lines.size()is unsigned, and so is then the sum and the difference on the RHS.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.