我有一个奇怪的问题,VS2005和2010都有。我有一个for循环,其中调用了一个内联函数,本质上是这样的(C ++,仅用于说明目的):
inline double f(int a)
{
if (a > 100)
{
// This is an error condition that shouldn't happen..
}
// Do something with a and return a double
}
然后是另一个函数的循环:
for (int i = 0; i < 11; ++i)
{
double b = f(i * 10);
}
现在发生的事情是,在调试版本中,一切正常。在发布所有优化的发布版本中,根据反汇编,这是编译的,以便i
直接使用* 10
而比较a > 100
变为a > 9
,我猜它应该是a > 10
。您是否有任何线索可以使编译器认为a > 9
是正确的方法?有趣的是,即使是周围代码中的微小更改(例如调试打印输出)也会使编译器使用i * 10
并将其与文字值100进行比较。
我知道这有点模糊,但我会对任何旧想法表示感谢。
修改
这是一个有希望再现的案例。我不认为它太大而不能粘贴在这里,所以这里有:
__forceinline int get(int i)
{
if (i > 600)
__asm int 3;
return i * 2;
}
int main()
{
for (int i = 0; i < 38; ++i)
{
int j = (i < 4) ? 0 : get(i * 16);
}
return 0;
}
我在我的机器上用VS2010进行了测试,它看起来和我遇到问题的原始代码一样糟糕。我在发布配置中使用IDE的默认空C ++项目模板编译并运行它。如你所见,永远不应该打破休息(37 * 16 = 592)。请注意,删除i < 4
会使其工作,就像在原始代码中一样。
答案 0 :(得分:6)
对于任何有兴趣的人来说,它都是VS编译器中的一个错误。由Microsoft确认并在报告后修复服务包。
答案 1 :(得分:2)
首先,如果您可以发布足够的代码以允许我们重现该问题,它会有所帮助。否则你只是要求进行心灵调试。
其次,偶尔会发生编译器无法在最高优化级别生成有效代码的情况,但更有可能的是,您的代码中只有一个错误。如果代码中某处存在未定义的行为,则意味着优化器所做的假设可能不成立,然后编译器最终会生成错误的代码。
但是,如果没有看到您的实际代码,我就无法获得更具体的代码。
答案 2 :(得分:0)
我所知道的唯一着名的优化错误(并且只有最高优化级别)是对操作优先级顺序的偶然修改(由于优化器执行的操作更改,寻找最快的计算方式)。你可以朝这个方向看(并且即使它们并非严格说来是必要的,也会加上一些括号,这就是为什么更多括号永远不会坏的原因),但坦率地说,这些错误很少见。
如上所述,没有更多代码,很难有任何确切的想法。
答案 3 :(得分:0)
首先,内联汇编会阻止某些优化,您应该使用__debugbreak()内在函数进行int3 breakpointing。编译器看到内联函数除断点之外没有任何影响,因此它将600除以16(注意:这受整数截断影响),因此它优化为debugbreak以触发38&gt; i&gt; = 37.所以它似乎在这方面起作用