0
#include <iostream>
#include <vector>

using std::cout;
using std::vector;
using std::endl;

int main() {

    vector<double> homework;
    homework.push_back(5.6);
    vector<double>::size_type size;
    size = homework.size();
    cout << size - 800 << endl;

}

Output:

$ ./a.out 
18446744073709550817

I understand that signed integer (and the overall result) is getting converted to unsigned and the resulting negative result is producing a positive result due to underflow.

Q: Why has this been implemented to behave this way ? Why can't I get the right answer here, which is -799

Ankur Agarwal
  • 21,824
  • 36
  • 127
  • 196
  • From my point of view `size - 800` should've been a compile time error (like "no operator - matches argumens unsinged long and int") rather than silently allowing crazy integer conversions. – user7860670 Nov 03 '18 at 19:41
  • 1
    It is unsigned because what is a negative size? If you want a signed value simply cast to a signed type. – Matt Nov 03 '18 at 19:41
  • 1
    You understand that the operands are converted to unsigned integers. Good. So why is it surprising the result is unsigned? – StoryTeller - Unslander Monica Nov 03 '18 at 19:43
  • 4
    You already have a good understanding of *what's* happening here. As far as the "why", I'm afraid the best answer you're going to get is "standard says so". – Silvio Mayolo Nov 03 '18 at 19:44
  • @SilvioMayolo You have given the most constructive and helpful comment so far. I think you also understood the question the best. – Ankur Agarwal Nov 03 '18 at 19:50
  • @abc But "standard says so" is not an answer. – user7860670 Nov 03 '18 at 19:51
  • Why it is this way is going to be opinion based I think. But you **can** get the right answer if you tell the compiler what you want: `int(size) - 800`. Beware that `size` fits in an `int` though. You should probably use `std::ptrdiff_t` as the largest integer type. – Galik Nov 03 '18 at 19:59
  • What type would that `-799` have? – melpomene Nov 03 '18 at 20:05
  • A little OT, but about the use of unsigned types in the STL, look at the linked video here: https://github.com/ericniebler/stl2/issues/182#issuecomment-287683189 – Bob__ Nov 03 '18 at 20:05
  • Try `size - 800.0`. I wish the language did not have this implicit conversion feature. (What VTT said, +1.) But alas, it does. It won't be changing any time soon. That ship has sailed. – Eljay Nov 03 '18 at 20:10
  • The question [Why must a short be converted to an int before arithmetic operations in C and C++?](https://stackoverflow.com/q/24371868/1708801) answers the basic question – Shafik Yaghmour Nov 03 '18 at 20:15
  • You are getting the correct answer for the program you wrote. The reason has to do with how close C++ is to the hardware. Unsigned integer wrapping his well defined in the architecture of the real and abstract machines C++ usually compiles for. There are a lot of programs that would stop working if this was not the case. – Richard Nov 03 '18 at 20:18
  • 1
    Possible duplicate of [what happens when i mix signed and unsigned types ?](https://stackoverflow.com/questions/25609091/what-happens-when-i-mix-signed-and-unsigned-types) – Robert Andrzejuk Nov 03 '18 at 20:29
  • As another source of information, see ["why is size_t unsigned"](https://stackoverflow.com/questions/10168079/why-is-size-t-unsigned) and related links. – HostileFork says dont trust SE Nov 03 '18 at 20:38
  • Also see [Implicit type conversion rules in C++ operators](https://stackoverflow.com/q/5563000/608639), [Integer promotion - what are the steps](https://stackoverflow.com/q/15255818/608639) and [How do promotion rules work when the signedness on either side of a binary operator differ?](https://stackoverflow.com/q/6770258/608639) – jww Nov 03 '18 at 20:55

1 Answers1

1

The reason for this is that expressions involving signed and unsigned types have all operands promoted to unsigned types.

According to the as-if rule, the expression size - 800 can also be interpreted as size + (-800) (which evidently Your compiler has done).

Thus -800 becomes a very large positive integer and the expression gives the result You are not expecting.

Robert Andrzejuk
  • 4,923
  • 2
  • 22
  • 30
  • 1
    `compiled into size + (-800)`? Why do you think so? Operator `-` is valid on its own in the language definition, and neither reduction to `+(negative)` is needed, nor guaranteed, so you cannot explain this behavior that way. The actual thing is that the .size() returns a `size_t`, and this one is **unsigned** and you are doing (unsigned rval) - (hard constant) which obviously returns an unsigned value.. – quetzalcoatl Nov 03 '18 at 20:39
  • https://godbolt.org/z/Aarx6s line 34 – Robert Andrzejuk Nov 03 '18 at 20:41
  • and what does it prove? compiler can do a lot of various transformations, half of the C++ spec is carefully worded so compilers can choose their own way. Can you point the chapter in the standard that guarantees it? – quetzalcoatl Nov 03 '18 at 20:44
  • I believe it's the "as if" rule. As `x - y` is the same as `x + (-y)` the compiler can do this without any hesitations. – Robert Andrzejuk Nov 03 '18 at 20:46
  • 1
    I would be willing to believe that it *can*, but it's not guaranteed to. Your answer makes it sound like the transformation is required of the compiler. – Silvio Mayolo Nov 03 '18 at 20:50
  • Fixed the explanation. How's that? – Robert Andrzejuk Nov 03 '18 at 21:40
  • 3
    This doesn't really involve the "as if" rule, which just means the observable side effects (including output) need to be the same as specified, no matter how the program actually gets that result. The rule is simply that the common type of `int` and `vector::size_type`, with `sizeof(vector::size_type)>=sizeof(int)`, is `vector::size_type`, for addition, subtraction, and several other binary operations. – aschepler Nov 03 '18 at 22:15