-1

I was humbly coding away when I ran into a strange situation involving checking the size of a vector. An isolated version of the issue is listed below:

#include <iostream>
#include <string>
#include <vector>

int main() {

  std::vector<std::string> cw = {"org","app","tag"};

  int j = -1;

  int len = cw.size();

  bool a = j>=cw.size();
  bool b = j>=len;


  std::cout<<"cw.size(): "<<cw.size()<<std::endl;
  std::cout<<"len: "<<len<<std::endl;

  std::cout<<a<<std::endl;
  std::cout<<b<<std::endl;

  return 0;
}

Compiling with both g++ and clang++ (with the -std=c++11 flag) and running results in the following output:

cw.size(): 3
len: 3
1
0

why does j >= cw.size() evaluate to true? A little experimenting that any negative value for j results in this weird discrepancy.

nmd
  • 93
  • 2
  • 8
  • 1
    Read about [integral conversions](https://en.cppreference.com/w/cpp/language/implicit_conversion). Note that `cw.zize()` returns an unsigned type. – Pete Becker Dec 30 '18 at 23:34
  • `cw.size()` is unsigned. In the comparison, the negative value of `j` gets coerced to a very large positive value. – Igor Tandetnik Dec 30 '18 at 23:34
  • 2
    Enable additional warnings (`-Wall -Wextra` for gcc/clang) and the compiler will likely warn you about stuff like this. –  Dec 30 '18 at 23:35
  • 2
    These comments should be answers – twoleggedhorse Dec 30 '18 at 23:36
  • Ah, definitely should've had the warnings up as @user10605163 suggested, pointed me right towards the problem. – nmd Dec 31 '18 at 03:21

1 Answers1

2

The pitfalls here are signed integral conversions that apply when you compare a signed integral value with an unsigned one. In such a case, the signed value will be converted to an unsigned one, and if the value was negative, it will get UINT_MAX - val + 1. So -1 will be converted to a very large number before comparison.

However, when you assign an unsigned value to a signed one, like int len = vec.size(), then the unsigned value will become a signed one, so (unsigned)10 will get (signed)10, for example. And a comparison between two signed ints will not convert any of the both operands and will work as expected.

You can simulate this rather easy:

int main() {
    int j = -1;

    bool a = j >= (unsigned int)10; // signed >= unsigned; will convert j to unsigned int, yielding 4294967295
    bool b = j >= (signed int)10; // signed >= signed; will not convert j

    cout << a << endl << b << endl;

    unsigned int j_unsigned = j;
    cout << "unsigned_j: " << j_unsigned << endl;
}

Output:

1
0
unsigned_j: 4294967295
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58