为什么减法溢出static_cast?

时间:2017-03-09 16:32:09

标签: c++ static-cast size-type

我了解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;
}

2 个答案:

答案 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_typeint的算术运算。在此混合中,无符号类型具有与int或更高相同的等级,这意味着无符号类型仍然会赢得&#34;:您的int被隐式转换回string::size_type并且计算在string::size_type的域中执行。您实际上会忽略转换为int

同时,将结果转换为int意味着您正在尝试转换不符合int范围的值。在这种情况下的行为是实现定义的。在现实生活中的2补码实现中,看到表示的简单截断并不罕见,这产生了正确的&#34;正确的&#34;结果。这不是一个好方法。

如果要将此减法作为签名减法执行,则必须将两个操作数转换为有符号类型,确保目标签名类型可以表示这两个值。

(从理论上讲,你可以将一个操作数转换为带符号的类型,但为此你需要选择一个可以代表整个范围string::size_type的类型。)