【问题标题】:Weird std::string::size() in a for loopfor 循环中奇怪的 std::string::size()
【发布时间】:2016-09-02 13:44:32
【问题描述】:

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

那么程序就不会进入循环,也不会打印“进入循环”

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

【问题讨论】:

  • 没有编译器警告?
  • 大多数编译器默认关闭有符号无符号警告,它会产生很多误报。一些编译器会在第二个示例中警告超出范围的赋值
  • 这就是为什么要对用于数学的数字进行签名。

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


【解决方案1】:

你是 unsigned 整数的受害者 :)

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

当编译器计算 input.size() - 1 时,这种类型变为 size_t(0) - 1,并且由于计算是使用 无符号 整数完成的,所以你得到一个非常大的整数而不是 -1(MSVC 32 -bit 编译器打印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 是一个无符号计算,即使后来分配给 int。编译器不会像这样计算0 - 1;它将 4294967295 转换为 int 。 (不保证给出相同的结果,但可能会)
【解决方案2】:

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

所以进入循环是因为0 &lt; SIZE_MAX 为真。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-05
    • 2019-02-11
    • 2019-04-30
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多