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

时间:2016-05-07 15:05:21

标签: c++ for-loop size unsigned unsigned-integer

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

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

然后程序不会进入循环并且不会打印“进入循环”

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

2 个答案:

答案 0 :(得分:6)

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

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

当编译器评估input.size() - 1时,这种变为size_t(0) - 1,并且由于计算是使用无符号整数完成的,而不是-1,因此得到一个非常大的整数number(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 }作为一个非常大的正整数,但是这个数字转换为(signedint,导致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和CASE1警告级别4 ,我高度建议)编译其/W4,您将获得 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

答案 1 :(得分:2)

input.size()是未签名的数量。所以当它为零时,减去1给出了它的类型的最大值(一个大的正整数,可能是SIZE_MAX)。

因此输入循环是因为0 < SIZE_MAX为真。

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