Visual Studio C ++编译器优化打破代码?

时间:2010-09-16 08:23:01

标签: c++ visual-studio visual-c++ compiler-optimization

我有一个奇怪的问题,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会使其工作,就像在原始代码中一样。

4 个答案:

答案 0 :(得分:6)

对于任何有兴趣的人来说,它都是VS编译器中的一个错误。由Microsoft确认并在报告后修复服务包。

答案 1 :(得分:2)

首先,如果您可以发布足够的代码以允许我们重现该问题,它会有所帮助。否则你只是要求进行心灵调试。

其次,偶尔会发生编译器无法在最高优化级别生成有效代码的情况,但更有可能的是,您的代码中只有一个错误。如果代码中某处存在未定义的行为,则意味着优化器所做的假设可能不成立,然后编译器最终会生成错误的代码。

但是,如果没有看到您的实际代码,我就无法获得更具体的代码。

答案 2 :(得分:0)

我所知道的唯一着名的优化错误(并且只有最高优化级别)是对操作优先级顺序的偶然修改(由于优化器执行的操作更改,寻找最快的计算方式)。你可以朝这个方向看(并且即使它们并非严格说来是必要的,也会加上一些括号,这就是为什么更多括号永远不会坏的原因),但坦率地说,这些错误很少见。

如上所述,没有更多代码,很难有任何确切的想法。

答案 3 :(得分:0)

首先,内联汇编会阻止某些优化,您应该使用__debugbreak()内在函数进行int3 breakpointing。编译器看到内联函数除断点之外没有任何影响,因此它将600除以16(注意:这受整数截断影响),因此它优化为debugbreak以触发38&gt; i&gt; = 37.所以它似乎在这方面起作用