为啥减法与static_cast溢出?

Posted

技术标签:

【中文标题】为啥减法与static_cast溢出?【英文标题】:why does subtraction overflow with static_cast?为什么减法与static_cast溢出? 【发布时间】:2017-07-30 17:58:34 【问题描述】:

我知道当s2 更大时s1.size() - s2.size() 下溢,因为它是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;

【问题讨论】:

你错过了signed + unsigned = unsigned的规则。 另请注意,您可以在完全不进行减法和强制转换的情况下做同样的事情。 return ((s1.size() &lt; s2.size()) ? true : false); @NathanOliver 或只是 return s1.size() &lt; s2.size(); @power_output 因为它需要static_cast这两个值才能工作 你需要阅读这个en.wikipedia.org/wiki/Two's_complement 【参考方案1】:

当你这样做时

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(),你实际上会得到一个负数。


需要注意的是,所有这些都可以通过使用小于运算符来避免。您的函数可以重写为

bool isShorter(const string &s1, const string &s2)

    return s1.size() < s2.size();

恕我直言,它更容易阅读和理解。

【讨论】:

【参考方案2】:

将“其中之一”转换为 int 会使您得到混合 string::size_typeint 的算术运算。在这种混合中,无符号类型与int 具有相同的等级或更高,这意味着无符号类型仍然“获胜”:您的int 被隐式转换回string::size_type,并且计算在@ 的域中执行987654327@。您对int 的转换实际上被忽略了。

同时,将结果转换为int 意味着您正在尝试转换一个不适合int 范围的值。这种情况下的行为是实现定义的。在现实生活中的 2's-complement 实现中,看到表示的简单截断并不罕见,这会产生“正确”的结果。不过,这不是一个好方法。

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

(理论上,您可以只将一个操作数转换为有符号类型,但为此您需要选择一种可以表示string::size_type 整个范围的类型。)

【讨论】:

以上是关于为啥减法与static_cast溢出?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 static_cast<int>(x) 而不是 (int)x?

为啥我可以将 static_cast void* 转换为 int* 而不能转换为 int*&?

static_cast 与 boost::lexical_cast

基本类型的 static_cast<T> 与 T(n)

dynamic_cast 与 typeid

static_cast 用法