我了解s1.size() - s2.size()
在s2
更大时会下溢,因为它会减去unsigned
。
为什么将它们转换为int
并不会导致整数减法?
为什么铸造整个东西给我正确的结果?我期望它评估括号内的内容,然后下溢会产生一个大数字,然后转换为int
不会产生影响。我错过了什么?
#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;
}
答案 0 :(得分:3)
当你这样做时
static_cast<int>(s1.size()) - s2.size()
您将s1.size()
转换为int
,然后从中减去s2.size()
,int
被提升为与s2.size()
相同的类型,然后被减去。这意味着你仍然有无符号整数减法,因为它不能是负数,它将回绕到更大的数字。它与执行s1.size() - s2.size()
没有什么不同。
你有同样的事情
static_cast<int>(s1.size() - s2.size())
带有可能的有符号整数溢出的额外奖励,这是未定义的行为。你仍然在进行无符号整数减法,所以如果s1
小于s2
,那么你可以将其包裹到一个大数字。
您需要做的是将s1.size()
和s2.size()
转换为有符号整数类型以获得烧结整数减法。这可能看起来像
static_cast<ptrdiff_t>(s1.size()) - static_cast<ptrdiff_t>(s2.size())
现在,如果s1.size()
小于s2.size()
,您实际上会得到一个负数。
应该注意的是,使用less than运算符可以避免所有这些。您的功能可以重写为
bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
其中,恕我直言,更容易阅读和理解。
答案 1 :(得分:2)
施放&#34;其中一个&#34;到int
会让您进行混合string::size_type
和int
的算术运算。在此混合中,无符号类型具有与int
或更高相同的等级,这意味着无符号类型仍然会赢得&#34;:您的int
被隐式转换回string::size_type
并且计算在string::size_type
的域中执行。您实际上会忽略转换为int
。
同时,将结果转换为int
意味着您正在尝试转换不符合int
范围的值。在这种情况下的行为是实现定义的。在现实生活中的2补码实现中,看到表示的简单截断并不罕见,这产生了正确的&#34;正确的&#34;结果。这不是一个好方法。
如果要将此减法作为签名减法执行,则必须将两个操作数转换为有符号类型,确保目标签名类型可以表示这两个值。
(从理论上讲,你可以将一个操作数转换为带符号的类型,但为此你需要选择一个可以代表整个范围string::size_type
的类型。)