我得到了以下代码:
#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失败。相反,测试正在以某种方式通过。这是一个编译器错误,还是我正在做一些未定义的事情?
发布于 2009-03-24 02:52:48
ISO14882:2003,第5节,第5款:
如果在表达式求值期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为是未定义的,除非这样的表达式是常量表达式(5.19),在这种情况下,程序是病态的。
(重点是我的。)所以,是的,行为是未定义的。该标准不保证在整数溢出/下溢的情况下的行为。
编辑:该标准似乎在其他地方的问题上略有冲突。
第3.9.1.4节规定:
被声明为无符号的
无符号整数应遵守以2n为模的算术法则,其中n是该特定大小的整数的值表示中的位数。
但是4.7.2节和.3说:
2)如果目标类型是无符号类型,则得到的值是与源整数(模2 n,其中n是用于表示无符号类型的位数)相同的最小无符号整数。注意:在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。
3)如果目标类型是有符号的,则如果可以在目标类型(和位字段宽度)中表示,则该值保持不变;否则,该值由实现定义。
(重点是我的。)
发布于 2009-03-24 02:50:47
我不确定,但我认为你可能遇到了一个bug。
我怀疑问题出在编译器处理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; )
发布于 2009-03-24 02:55:24
是的,我刚刚在Visual Studio2005上测试了这一点,它在Debug和Release中的表现绝对不同。我想知道2008年是否能解决这个问题。
有趣的是,它抱怨从size_t (.length的结果)到unsigned int的隐式强制转换,但生成糟糕的代码没有任何问题。
https://stackoverflow.com/questions/675976
复制相似问题