如果我使用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”(进入循环)
我在想为什么会这样? 这两段代码对我来说似乎是一样的。
您是无符号整数的受害者:)
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。