简体   繁体   English

通常的算术转换如何工作?

[英]How do usual arithmetic conversions work?

I was running this code in VS2019:我在 VS2019 中运行这段代码:

#include<iostream>
#include<string>
#include<typeinfo>
using namespace std;

int main() {
    string mystring = "hello world";
    for (int j = 0; j < 10; j++) {
        if (mystring[j + 1] == 'w') {
            cout<<"string contains w letter\n";
        }
        else {
            continue;
        }
        return 0;
    }
}

And I realized that when I run it on Debug mode on an x86 platform, everything is ok, but if I change the platform to x64, the following warning appears:我意识到,当我在 x86 平台上以调试模式运行它时,一切正常,但如果我将平台更改为 x64,则会出现以下警告:

C26451 Arithmetic overflow: Using operator '+' on a 4-byte value and then casting the result to an 8-byte value. C26451 算术溢出:对 4 字节值使用运算符“+”,然后将结果转换为 8 字节值。 Cast the value to the wider type before calling operator '+' to avoid overflow (io.2).在调用运算符“+”之前将值转换为更广泛的类型以避免溢出 (io.2)。

It seems to be related to Usual arithmetic conversions , such that, if the operands are of different types, a conversion is applied to one of them before calculation.它似乎与通常的算术转换有关,因此,如果操作数属于不同类型,则在计算之前将转换应用于其中一个。 But if they are equal, that still happens?但如果他们是平等的,那还会发生吗?

If I print typeid(j).name() and typeid(1).name() , it prints int for both, so what is the reason for this warning?如果我打印typeid(j).name()typeid(1).name() ,它会为两者打印int ,那么这个警告的原因是什么? The warning is fixed if I change the if condition to (mystring[j + static_cast<__int64>(1)] == 'w') .如果我将if条件更改为(mystring[j + static_cast<__int64>(1)] == 'w') ,则警告已修复。 The explanation, I think, should be that the number '1' is not considered of type int on x64, or it is but occupies different bits of memory than the int type on x64.我认为,解释应该是数字'1'不被认为是x64上的int类型,或者它占用了memory的不同位,而不是x64上的int类型。

I would really like to clarify the issue, thanks.我真的很想澄清这个问题,谢谢。

The "C26451" warning is not a standard compiler warning. “C26451”警告不是标准的编译器警告。 It's part of the C++ Code Guidelines Checker which is giving you 'recommendations'.它是 C++ 代码指南检查器的一部分,它为您提供“建议”。 For more on this feature, see Microsoft Docs .有关此功能的更多信息,请参阅Microsoft Docs

In C++ Core Guidelines the specific recommendation the checker is using here is: ES.103: Don't overflow .C++ 核心指南中,检查器在这里使用的具体建议是: ES.103:不要溢出

The reason this only happens in x64 is because size_t is 64-bits while int is 32-bits.这只发生在 x64 中的原因是size_t是 64 位,而int是 32 位。 In x86, both int and size_t are 32-bits.在 x86 中, intsize_t都是 32 位。

The std::string operator[] takes a size_t . std::string运算符[] 采用size_t The cleanest simplest fix here is:这里最干净最简单的修复是:

for (size_t j= 0; j <10; j++)

You could also address this by explicitly promoting the int to size_t before the addition takes place:您还可以通过在添加之前将int显式提升为size_t来解决此问题:

if (mystring[size_t(j) + 1] == 'w') {

You could also ignore the warning by adding:您还可以通过添加以下内容来忽略警告:

#pragma warning(disable : 26451)

Or you could disable the C++ Core Guidelines Checker.或者您可以禁用 C++ 核心指南检查器。

This is how the std::string [] operator defined.这就是std::string [] operator的定义方式。 It takes std::size_t.它需要 std::size_t。

char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;

That's where the casting is taking place: int -> size_t.这就是强制转换发生的地方:int -> size_t。

https://www.learncpp.com/cpp-tutorial/fixed-width-integers-and-size-t/ https://www.learncpp.com/cpp-tutorial/fixed-width-integers-and-size-t/

edit: See Chuck Walbourn answer编辑:见 Chuck Walbourn 的回答

It seems to be related to Usual arithmetic conversions, such that, if the operands are of different types, a conversion is applied to one of them before calculation.它似乎与通常的算术转换有关,因此,如果操作数属于不同类型,则在计算之前将转换应用于其中一个。 But if they are equal, that still happens?但如果他们是平等的,那还会发生吗?

Your conclusion is incorrect.你的结论是错误的。

VS thinks that j + 1 has the potential to overflow. VS 认为j + 1有溢出的可能。 It recommends that you perform the arithmetic operation, + , on a wider integral type to reduce the chances of overflow.它建议您对更广泛的整数类型执行算术运算+以减少溢出的机会。 Note that static_cast<std::size_t>(j) + 1 could, in theory, still overflow but VS does not care about that.请注意,理论上static_cast<std::size_t>(j) + 1仍然可能溢出,但 VS 并不关心这一点。

You don't get the warning in x86 mode since the size of std::size_t and int are same on that platform.您不会在 x86 模式下收到警告,因为该平台上std::size_tint的大小相同。

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

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