for 循环中的奇怪行为 - 一个错误?

问题描述 投票:0回答:1

我正在 Windows 7 计算机上使用 Visual Studio 2012,当尝试运行以下代码片段(在 x64 模式下使用默认 VC11 C++ 编译器编译)时,断言失败,这意味着永远不会进入内部循环:

void loopTest1()
{
    const unsigned int k = 1;

    for (int m=0; m<3; ++m)
    {
        int acc = 0;

        for (int n=m-k; n<=m+k; ++n)
        {
            if (n<0 || n>=3) continue;

            ++acc;
        }

        assert (acc>0);

        cout << "acc: " << acc << endl;
    }
}

现在我更改内循环的结束条件:

void loopTest2()
{
    const unsigned int k = 1;

    for (int m=0; m<3; ++m)
    {
        int acc = 0;

        int l = m+k; // this line was added
        for (int n=m-k; n<=l; ++n) // m+k was replaced by l
        {
            if (n<0 || n>=3) continue;

            ++acc;
        }

        assert (acc>0);

        cout << "acc: " << acc << endl;
    }
}

然后我得到了正确的结果:

acc: 2
acc: 3
acc: 2

当我用硬编码 1 替换

const unsigned int k
时,它也有效:

void loopTest3()
{
    //const unsigned int k = 1;

    for (int m=0; m<3; ++m)
    {
        int acc = 0;

        for (int n=m-1; n<=m+1; ++n) //replaced k with 1
        {
            if (n<0 || n>=3) continue;

            ++acc;
        }

        assert (acc>0);

        cout << "acc: " << acc << endl;
    }
}

编译器是否执行了一些错误的优化? 或者是否有任何具体原因,为什么第一种情况下的行为至少是意外的?

c++ visual-studio-2012
1个回答
3
投票

您的

int m
将晋升为
unsigned int
。在第一个循环中,这意味着
m-k
等于-1作为无符号值,这是最大的无符号值并且明显大于
m+k
(当比较
n
时,它会被提升)。从长远来看,您最终会得到
n
是 -1 的无符号表示,而
m+k
是 1。当然,当您将 -1 无符号存储到有符号整数中时,它会溢出,并且在技术上是未定义的行为。它很可能保持其 -1 表示,然后提升回最大无符号值。

以下是第一次迭代的总结:

迭代 1:
米:0
k:1u
n=m-k: -1u = max uint, 存储为signed int
m+k: 1u
n<=m+k --> 最大单位 <= 1u

在第二个示例中,与其他有符号整数相比,

n
不会被提升,并且它比较两个有符号整数。在你的第三个中,没有任何内容是未签名的。

© www.soinside.com 2019 - 2024. All rights reserved.