通常的算术转换如何工作?
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 中,int
和 size_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_t
和 int
的大小在该平台上相同。
我在 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 中,int
和 size_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_t
和 int
的大小在该平台上相同。