为啥减法与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() < s2.size()) ? true : false);
@NathanOliver 或只是 return s1.size() < 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_type
和 int
的算术运算。在这种混合中,无符号类型与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*&?