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

发布于 2024-07-15 19:55:04 字数 564 浏览 6 评论 0原文

我有以下代码:

#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 失败。 相反,测试以某种方式通过了。 这是编译器错误,还是我在某处做了一些未定义的事情?

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

If I compile in MSVC with full optimizations, the output I get is "-1?". If I compile in Debug mode (no optimizations), I get no output (expected.)

I thought the standard guaranteed that unsigned integers overflowed in a predictable way, so that when i = (unsigned int)(-1), i+1 = 0, and the loop condition i + 1 >= 1 fails. Instead, the test is somehow passing. Is this a compiler bug, or am I doing something undefined somewhere?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

烈酒灼喉 2024-07-22 19:55:04

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

优化器看到

i + 1 >= 1;

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

i >= (1-1);

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

请参阅此新闻组讨论 此处

I remember having this problem in 2001. I'm amazed it's still there. Yes, this is a compiler bug.

The optimiser is seeing

i + 1 >= 1;

Theoretically, we can optimise this by putting all of the constants on the same side:

i >= (1-1);

Because i is unsigned, it will always be greater than or equal to zero.

See this newsgroup discussion here.

少年亿悲伤 2024-07-22 19:55:04

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

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

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

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

第 3.9.1.4 节说:

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

但第 4.7.2 和 .3 节说:

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

3) 如果目标类型有符号,并且可以用目标类型(和位域宽度)表示,则该值不会改变; 否则,该值是实现定义的。

(强调我的。)

ISO14882:2003, section 5, paragraph 5:

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined, unless such an expression is a constant expression (5.19), in which case the program is ill-formed.

(Emphasis mine.) So, yes, the behavior is undefined. The standard makes no guarantees of behavior in the case of integer over/underflow.

Edit: The standard seems slightly conflicted on the matter elsewhere.

Section 3.9.1.4 says:

Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2 n where n is the number of bits in the value representation of that particular size of integer.

But section 4.7.2 and .3 says:

2) If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2 n where n is the number of bits used to represent the unsigned type). [Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). ]

3) If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.

(Emphasis mine.)

忆梦 2024-07-22 19:55:04

我不确定,但我认为您可能遇到了错误。

我怀疑问题在于编译器如何处理 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; )

I'm not certain, but I think you are probably running foul of a bug.

I suspect the trouble is in how the compiler is treating the for control. I could imagine the optimizer doing:

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

Whether that is what is happening is another matter, but it might be enough to confuse the optimizer.

You would probably be better off using a more standard loop formulation:

for (unsigned i = a.length()-1; i-- > 0; )
我的痛♀有谁懂 2024-07-22 19:55:04

是的,我刚刚在 Visual Studio 2005 上对此进行了测试,它在调试和发布中的表现肯定有所不同。 我想知道2008年是否解决了这个问题。

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

Yup, I just tested this on Visual Studio 2005, it definitely behaves differently in Debug and Release. I wonder if 2008 fixes it.

Interestingly it complained about your implicit cast from size_t (.length's result) to unsigned int, but has no problem generating bad code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文