2

我在这里有一个特殊的问题,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

4 回答 4

6

对于任何感兴趣的人,结果证明这是 VS 编译器中的一个错误。经 Microsoft 确认并在报告后的服务包中修复。

于 2013-03-01T07:10:06.270 回答
2

首先,如果您可以发布足够多的代码让我们重现该问题,那将会有所帮助。否则,您只是要求进行心理调试。

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

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

于 2010-09-16T08:27:31.610 回答
0

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

如前所述,如果没有更多代码,很难有任何精确的想法。

于 2010-09-16T08:42:24.150 回答
0

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

于 2010-09-16T10:19:39.340 回答