I understand that s1.size() - s2.size()
underflows when s2
is bigger because it's subtraction of unsigned
.
Why casting one them to int
doesn't result in integer subtraction?
Why casting the whole thing gives me the correct result? I expected it to evaluate what is inside parentheses, then underflow which would give a big number and then the cast to int
would not make difference. What am I missing?
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
bool isShorter(const string &s1, const string &s2) {
return (static_cast<int>(s1.size()) - s2.size() < 0) ? true : false; // underflows
//return (static_cast<int>(s1.size() - s2.size()) < 0) ? true : false; // this works
}
int main() {
string s, t;
getline(cin, s);
getline(cin, t);
cout << "s: " << s << endl;
cout << "t: " << t << endl;
cout << "printing shorter string of the two..." << endl;
cout << ((isShorter(s, t)) ? s : t) << endl;
}
When you do
static_cast<int>(s1.size()) - s2.size()
You convert s1.size()
to a int
and then when you subtract s2.size()
from it that int
is promoted to the same type as s2.size()
and then it is subtracted. This means you still have unsigned integer subtraction and since that can't ever be negative it will wrap around to a larger number. It is no different from doing s1.size() - s2.size()
.
You have the same thing with
static_cast<int>(s1.size() - s2.size())
With the added bonus of possible signed integer overflow which is undefined behavior. You are still doing unsigned integer subtraction so if s1
is smaller than s2
than you wrap around to a large number.
What you need to do is convert both s1.size()
and s2.size()
to a signed integer type to get singed integer subtraction. That could look like
static_cast<ptrdiff_t>(s1.size()) - static_cast<ptrdiff_t>(s2.size())
And now you will actually get a negative number if s1.size()
is less than s2.size()
.
It should be noted that all of this can be avoided by using less than operator. Your function can be rewritten to be
bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
which, IMHO, is much easier to read and understand.