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

How do usual arithmetic conversions work?

我在 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;
    }
}

而且我意识到当我在 x86 平台上 运行 它处于调试模式时,一切正常,但是如果我将平台更改为 x64,则会出现以下警告:

C26451 Arithmetic overflow: Using operator '+' on a 4-byte value and then casting the result to an 8-byte value. Cast the value to the wider type before calling operator '+' to avoid overflow (io.2).

好像和Usual arithmetic conversions有关,如果操作数是不同的类型,在计算之前先对其中一个进行转换。但如果它们相等,那仍然会发生?

如果我打印 typeid(j).name()typeid(1).name(),它会为两者打印 int,那么这个警告的原因是什么?如果我将 if 条件更改为 (mystring[j + static_cast<__int64>(1)] == 'w'),则警告已修复。我认为,解释应该是数字“1”在 x64 上不被视为 int 类型,或者它占用的内存位与 x64 上的 int 类型不同。

我真的很想澄清这个问题,谢谢。

“C26451”警告不是标准编译器警告。它是 C++ 代码指南检查器的一部分,它为您提供 'recommendations'。有关此功能的更多信息,请参阅 Microsoft Docs.

C++ Core Guidelines the specific recommendation the checker is using here is: ES.103: Don't overflow.

这只发生在 x64 中的原因是因为 size_t 是 64 位而 int 是 32 位。在 x86 中,intsize_t 都是 32 位。

std::string operator[] 采用 size_t。这里最干净最简单的修复是:

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

您还可以通过在添加发生之前将 int 显式提升为 size_t 来解决此问题:

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

您也可以通过添加忽略警告:

#pragma warning(disable : 26451)

或者您可以禁用 C++ Core Guidelines Checker。

std::string [] operator 就是这样定义的。需要 std::size_t.

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

这就是进行转换的地方:int -> size_t。

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

编辑:参见 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?

你的结论不正确。

VS认为j + 1有溢出的可能。它建议您对更宽的整数类型执行算术运算 +,以减少溢出的机会。请注意,理论上 static_cast<std::size_t>(j) + 1 仍可能溢出,但 VS 不关心这一点。

您在 x86 模式下不会收到警告,因为 std::size_tint 的大小在该平台上相同。