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
如果我使用 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