提问者:小点点

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


如果我使用input.size()-1作为for循环条件,程序将打印“Enterted 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;
}

则程序将不会进入循环,也不会打印“Enterted the loop”(进入循环)

我在想为什么会这样? 这两段代码对我来说似乎是一样的。


共2个答案

匿名用户

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

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)

相当于:

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,我强烈建议使用这一级别),您会收到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

匿名用户

input.size()是无符号量。 因此当它为零时,减去1就会得到其类型的最大值(一个大的正整数,可能是size_max)。

所以进入循环是因为0<; size_max为true。

但是当您将这个大正数转换为int时,该数字超出了int的范围。 因此会发生实现定义的行为,这可能会产生checksize==-1。 则循环不会被输入,因为0<; -1为false。