3
int main() {
    vector<int> v;
    if (0 < v.size() - 1) {
        printf("true");
    } else {
        printf("false");
    }
}

It prints true which indicates 0 < -1

user3288177
  • 479
  • 1
  • 4
  • 9
  • 5
    While you've been already given some great answers below, I would like to point out that there would be no such question if you simply did `std::cout << v.size() - 1;`. You seem to assume that `v.size() - 1` would equal `-1`. In such cases, it's generally a good idea to back up such assumptions by simply printing the value. Or, which would be even better, learn how to effectively use a good debugger. – Fureeish Jan 19 '19 at 01:10
  • 1
    Unrelated, but simply solving the inequality and doing `v.size() >= 2` might me better? – L. F. Jan 19 '19 at 04:55

3 Answers3

8

std::vector::size() returns an unsigned integer. If it is 0 and you subtract 1, it underflows and becomes a huge value (specifically std::numeric_limits<std::vector::size_type>::max()). The comparison works fine, but the subtraction produces a value you did not expect.

For more about unsigned underflow (and overflow), see: C++ underflow and overflow

The simplest fix for your code is probably if (1 < v.size()).

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
4

v.size() returns a result of size_t, which is an unsigned type. An unsigned value minus 1 is still unsigned. And all non-zero unsigned values are greater than zero.

selbie
  • 100,020
  • 15
  • 103
  • 173
4

std::vector<int>::size() returns type size_t which is an unsigned type whose rank is usually at least that of int.

When, in a math operation, you put together a signed type with a unsigned type and the unsigned type doesn't have a lower rank, the signed typed will get converted to the unsigned type (see 6.3.1.8 Usual arithmetic conversions (I'm linking to the C standard, but rules for integer arithmetic are foundational and need to be common to both languages)).

In other words, assuming that size_t isn't unsigned char or unsigned short (it's usually unsigned long and the C standard recommends it shouldn't be unsigned long long unless necessary)

(size_t)0 - 1

gets implicitly translated to

(size_t)0 - (size_t)1

which is a positive number equal to SIZE_MAX (-1 cannot be represented in an unsigned type so it gets converted converted by formally "repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type" (6.3.1.3p)).

0 is always less than SIZE_MAX.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • "an unsigned type that's at least as wide as int." Any reference to support that? (It is certainly commonly implemented that way.) – chux - Reinstate Monica Jan 19 '19 at 03:01
  • @chux AFAIK, no. But, for [example](https://stackoverflow.com/a/131833/), "The `size_t` type may be bigger than, equal to, or smaller than an `unsigned int`, and your compiler might make assumptions about it for optimization." (You know `sizeof(unsigned int) = sizeof(int)`) – L. F. Jan 19 '19 at 05:07
  • 1
    @chux Thanks for the comment. I searched through the C standard and POSIX and there's no indication `size_t` couldn't _theoretically_ be `unsigned char` or `unsigned short`, either of which would change the result of that logical expression from true to false. I've edited the answer accordingly. – Petr Skocik Jan 19 '19 at 10:00