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

まず、問題を再現できるように十分なコードを投稿していただけると助かります。それ以外の場合は、精神的なデバッグを求めているだけです。

第 2 に、コンパイラが最高の最適化レベルで有効なコードを生成できないことがありますが、コードのどこかにバグがある可能性が高いです。コードのどこかに未定義の動作がある場合、それはオプティマイザーによる仮定が成り立たない可能性があり、コンパイラーが悪いコードを生成する可能性があることを意味します。

しかし、あなたの実際のコードを見なければ、これ以上具体的なことはわかりません。

于 2010-09-16T08:27:31.610 に答える
0

まず、インラインアセンブリは特定の最適化を妨げます。これは、int3ブレークポイントに固有の__debugbreak()を使用する必要があります。コンパイラは、インライン関数がブレークポイント以外の効果を持たないことを確認するため、600を16で除算します(注:これは整数の切り捨ての影響を受けます)。したがって、debugbreakに最適化して、38> i>=37でトリガーします。この目的に取り組むために

于 2010-09-16T10:19:39.340 に答える
0

私が知っている最適化に関する唯一の有名なバグ (および最高の最適化レベルのみ) は、操作の優先順位がときどき変更されることです (オプティマイザーによって実行される操作が変更され、計算の最速の方法を探しているためです)。この方向に目を向けることもできます (厳密には必要ではありませんが、括弧を付けることもできます。そのため、括弧を増やすことは決して悪いことではありません) が、率直に言って、この種のバグは非常にまれです。

述べたように、より多くのコードがなければ、正確なアイデアを持つことは困難です。

于 2010-09-16T08:42:24.150 に答える