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

Weird std::string::size() in a for loop

如果我使用 input.size() - 1 作为 for 循环条件,程序将打印 "Entered the loop"。

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

但是,如果我将 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;
}

那么程序不会进入循环,不会打印"Entered the loop"

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

input.size() 是无符号数。所以当它为零时,减去 1 得到其类型的最大值(一个大的正整数,可能 SIZE_MAX)。

所以进入循环,因为0 < SIZE_MAX为真。

但是当您将这个大的正数转换为 int 时,该数字超出了 int 的范围。所以 实现定义的 行为发生了,这可能会产生 checksize == -1。然后你的循环没有进入因为 0 < -1 是 false.

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

std::string::size() returns 一个 无符号整数 (类型等同于 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)

相当于:

for (int i = 0; i < /* very big positive number */; ++i)

这将打印您的消息很多次。

相反,在第二种情况下,当您评估 input.size() - 1 然后将其分配给 int 变量(默认情况下为 signed)时,编译器仍会计算 size_t(0) - 1 作为一个非常大的正整数,但随后这个数字被转换为 (signed) int,导致 checksize 被初始化为 -1,并且你的永远不会执行循环:

for (int i = 0; i < checksize /* -1 */; ++i)

考虑这个可编译代码:

#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
}

如果您使用 MSVC 和 /W4 编译它的 CASE1 警告级别 4,我 高度评价 建议),你会得到 warning 你的 for 循环条件:

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

test.cpp(10) : warning C4018: '<' : signed/unsigned mismatch

这通常表明您的代码有问题。

相反,在没有 CASE1 的情况下进行编译不会给出任何警告和以下输出(这表明 for 循环体从未执行):

cl /EHsc /W4 /nologo test.cpp

input.size() - 1  == 4294967295
SIZE_MAX          == 4294967295
checkSize == -1