简体   繁体   English

为什么减法会与static_cast溢出?

[英]why does subtraction overflow with static_cast?

I understand that s1.size() - s2.size() underflows when s2 is bigger because it's subtraction of unsigned . 我知道s2较大时s1.size() - s2.size()下溢,因为它是unsigned的减法。 Why casting one them to int doesn't result in integer subtraction? 为什么将它们强制转换为int不会导致整数减法? 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. 我希望它可以评估括号内的内容,然后下溢将产生很大的数字,然后将其强制转换为int不会有任何影响。 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. 您将s1.size()转换为int ,然后s2.size()减去s2.size() ,则int被提升为与s2.size()相同的类型,然后被减去。 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() . 这与执行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. 您仍在进行无符号整数减法,因此,如果s1小于s2 ,则您将其环绕为一个大数。

What you need to do is convert both s1.size() and s2.size() to a signed integer type to get singed integer subtraction. 您需要做的是将s1.size()s2.size()都转换为有符号整数类型,以得到单数减法。 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() . 现在,如果s1.size()小于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. 恕我直言,这更容易阅读和理解。

Casting "one of them" to int leaves you with arithmetic operation that mixes string::size_type and int . 将“其中之一”强制转换为int会使您进行混合string::size_typeint算术运算。 In this mix the unsigned type has the same rank as int or higher, which means that the unsigned type still "wins": your int is implicitly converted back to string::size_type and the calculations are performed in the domain of string::size_type . 在这种混合中,无符号类型与int或更高级别具有相同的等级,这意味着无符号类型仍然“胜出”:您的int被隐式转换回string::size_type ,并且计算在string::size_type的域中执行。 Your conversion to int is effectively ignored. 您到int转换实际上被忽略。

Meanwhile, casting the result to int means that you are attempting to convert a value that does not fit into int 's range. 同时,将结果强制转换为int意味着您正在尝试转换不适合int范围的值。 The behavior in such cases is implementation defined. 这种情况下的行为是由实现定义的。 In real-life 2's-complement implementations it is not unusual to see a simple truncation of the representation, which produces the "correct" result. 在现实生活中2的补码实现中,看到表示形式的简单截断会产生“正确”的结果并不罕见。 This is not a good approach though. 但是,这不是一个好方法。

If you want to perform this subtraction as a signed one, you have to convert both operands to signed types, making sure that the target signed type can represent both values. 如果要将此减法作为带符号的减法执行,则必须将两个操作数都转换为带符号的类型,并确保目标带符号的类型可以表示两个值。

(Theoretically, you can get away with converting just one operand to signed type, but for that you'd need to choose a type that can represent the entire range of string::size_type .) (理论上,您可以避免只将一个操作数转换为带符号类型,但是为此,您需要选择一种可以代表整个string::size_type范围的类型。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM