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

8

I've got the following code:

#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 >= 1失败。但是,测试却通过了。这是编译器bug还是我在某个地方做了未定义的事情?
4个回答

8
我记得在2001年就遇到过这个问题。我很惊讶它仍然存在。是的,这是一个编译器的错误。
优化器看到了:
i + 1 >= 1;

理论上,我们可以通过将所有常量放在同一侧来进行优化:
i >= (1-1);

由于i是无符号的,它始终大于或等于零。

请查看此新闻组讨论此处


4

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

如果在计算表达式时结果在其类型的可表示范围之外或者没有数学定义,则行为是未定义的,除非这样的表达式是常量表达式(5.19),在这种情况下程序是不合法的。

(强调是我的。)因此,是的,行为是未定义的。对于整数溢出/下溢的情况,标准没有任何保证。

编辑:标准在其他地方似乎存在轻微冲突。

第3.9.1.4节说:

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

但第4.7.2和.3节说:

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

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

(强调是我的。)


嗯。其他人(在不同的网站上)在引用标准的第4.7节: http://dev.feuvan.net/docs/isocpp/conv.html 他们使用这个来证明它已经被定义了。 - Andrew Shepherd
从3.9.1 4以及其脚注中,我得出了无符号整数是一个例外的印象:由于在mod 2^n的算术中添加了1,因此结果不可能超出值的范围,对吗? - Etienne Vouga
假设这是相关的5.5,我猜它归结于“如果结果在数学上有定义”。正如Etienne所指出的,对于无符号整数,溢出是有定义的,但我不确定下溢情况。负数的模算术在C++中是实现定义的。那么这里的下溢是如何工作的? - jalf
编译器不应该防止未定义的操作,这是程序员的责任。未定义行为的整个意义在于编译器可以自由地做自己想做的事情。它为什么应该给出诊断呢? - jalf
因为这可能不是程序员想要的。 - greyfade
显示剩余8条评论

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; )

0

没错,我刚在Visual Studio 2005上测试了一下,它在Debug和Release模式下的行为确实不同。我想知道2008年的版本是否修复了这个问题。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接