MSVC ++:无符号整数和溢出的奇怪性

时间:2009-03-24 02:36:00

标签: c++ standards

我有以下代码:

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    string a = "a";
    for(unsigned int i=a.length()-1; i+1 >= 1; --i)
    {
        if(i >= a.length())
        {
            cerr << (signed int)i << "?" << endl;
            return 0;
        }
    }
}

如果我使用完全优化在MSVC中编译,我得到的输出是“-1?”。如果我在调试模式下编译(没有优化),我没有输出(预期。)

我认为标准保证无符号整数以可预测的方式溢出,因此当i =(unsigned int)( - 1)时,i + 1 = 0,并且循环条件i + 1&gt; = 1失败。相反,测试以某种方式通过。这是一个编译器错误,还是我在某处做某些未定义的事情?

4 个答案:

答案 0 :(得分:8)

我记得在2001年遇到这个问题。我很惊讶它仍然存在。是的,这是一个编译器错误。

优化者正在看

i + 1 >= 1;

理论上,我们可以通过将所有常量放在同一侧来优化这一点:

i >= (1-1);

因为 i 是无符号的,所以它总是大于或等于零。

请参阅此新闻组讨论here

答案 1 :(得分:4)

ISO14882:2003,第5节,第5段:

  

如果在评估表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义,除非此类表达式是常量表达式( 5.19),在这种情况下,该程序是不正确的。

(强调我的。)所以,是的,行为是未定义的。在整数溢出/下溢的情况下,该标准不保证行为。

编辑:标准似乎在其他地方略有冲突。

第3.9.1.4节说:

  

无符号整数,声明为无符号整数,应遵守算术模2 n的定律,其中n是该特定整数大小的值表示中的位数。

但第4.7.2和.3节说:

  

2)如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模2 n,其中n是用于表示无符号类型的位数)。 [注意:在二进制补码表示中,此转换是概念性的,并且位模式没有变化(如果没有截断)。 ]

     

3)如果目标类型是有符号的,如果它可以在目标类型(和位字段宽度)中表示,则该值不变; 否则,该值是实现定义的。

(强调我的。)

答案 2 :(得分:1)

我不确定,但我认为你可能犯了一个错误。

我怀疑问题在于编译器如何处理for控件。我可以想象优化器在做什么:

for(unsigned int i=a.length()-1; i+1 >= 1; --i)   // As written

for (unsigned int i = a.length()-1; i >= 0; --i) // Noting 1 appears twice

for (unsigned int i = a.length()-1; ; --i)   // Because i >= 0 at all times

这是否正在发生的事情是另一回事,但它可能足以混淆优化器。

使用更标准的循环配方可能会更好:

for (unsigned i = a.length()-1; i-- > 0; )

答案 3 :(得分:0)

是的,我刚刚在Visual Studio 2005上对此进行了测试,它在Debug和Release中的表现肯定不同。我想知道2008年是否会修复它。

有趣的是,它抱怨你从size_t(.length的结果)到unsigned int的隐式转换,但生成错误代码没有问题。