for循环中奇怪的std :: string :: size()

lig*_*rek 2 c++ size unsigned for-loop unsigned-integer

如果我input.size() - 1用作for循环条件,程序将打印"进入循环" .

std::string input;
input = {""};
int i = 0;
for (; i < input.size() - 1; ++i)
{
    cout << "Entered the loop" << endl;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我将值传递input.size() -1给整数(checksize):

std::string input;
input = {""};
int checksize = input.size() - 1;
int i = 0;
for (; i < checksize; ++i)
{
    cout << "Entered the loop" << endl;
}
Run Code Online (Sandbox Code Playgroud)

然后程序将不会进入循环并且不会打印"进入循环"

我想知道为什么会这样?看来这两段代码对我来说是一样的.

Mr.*_*C64 6

你是无符号整数的受害者:)

std::string::size()返回无符号整数(类型等于size_t).

当编译器评估时input.size() - 1,这种情况变为size_t(0) - 1,并且由于计算是使用无符号整数完成的,而不是-1,因此得到一个非常大的整数(MSVC 32位编译器打印4294967295,对应于最大32位无符号整数值)2^32 - 1).

所以这个循环:

for (int i = 0; i < input.size() - 1; ++i)
Run Code Online (Sandbox Code Playgroud)

有点像:

for (int i = 0; i < /* very big positive number */; ++i)
Run Code Online (Sandbox Code Playgroud)

这将打印信息许多倍.

相反,在第二种情况下,当你评估input.size() - 1,然后将其分配给一个int变量(它是signed通过缺省值),编译器仍然计算size_t(0) - 1作为一个非常大的正整数,但随后这个号码被转换为(signed)int,从而产生checksize被用-1,初始化,你的循环永远不会执行:

for (int i = 0; i < checksize /* -1 */; ++i)
Run Code Online (Sandbox Code Playgroud)

考虑这个可编译的代码:

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

int main() 
{
    string input;

#ifdef CASE1
    for (int i = 0; i < input.size() - 1; ++i)
    {
        cout << "Entered the loop\n";
    }
#else
    cout << "input.size() - 1  == " << (input.size() - 1) << '\n';
    cout << "SIZE_MAX          == " << SIZE_MAX << '\n';

    int checkSize = input.size() - 1;
    cout << "checkSize == " << checkSize << '\n';

    for (int i = 0; i < checkSize; ++i)
    {
        cout << "Entered the loop\n";
    }
#endif
}
Run Code Online (Sandbox Code Playgroud)

如果您编译它CASE1与MSVC和/W4(警戒水位4,我强烈建议),你会得到一个警告,为您的for循环条件:

cl /EHsc /W4 /nologo /DCASE1 test.cpp

test.cpp(10) : warning C4018: '<' : signed/unsigned mismatch
Run Code Online (Sandbox Code Playgroud)

通常会向您指出您的代码出了问题.

相反,编译没有CASE1,没有提供警告和以下输出(这表明for循环的主体永远不会被执行):

cl /EHsc /W4 /nologo test.cpp

input.size() - 1  == 4294967295
SIZE_MAX          == 4294967295
checkSize == -1
Run Code Online (Sandbox Code Playgroud)

  • `input.size() - 1`是无符号计算,即使后来被赋值为int.编译器不会像这样计算"0 - 1"; 它将4294967295转换为int.(不保证给出相同的结果,但可能会) (2认同)