1

これに対する答えを2日間探しましたが、成功しませんでした。私はこれまでこの問題に遭遇したことがないので、最善を尽くします。我慢してください。

1 年以上前に作成した C++ プロジェクトに戻りましたが、当時は問題なく実行されていました。先日、同じプログラムを実行しようとしていたときに、この興味深く、信じられないほど厄介な問題に遭遇しました。コードは次のようなものでした:

file.h

...
short id;
...

file.cc

id = 0;
while (id < some_large_number)
{
   id = foo();  
   if (id == 2)
   {
      //do something
   }
   else if (id == 2900)
   {
      //do something
   }
   else if (id == 30000)
   {
      //do something
   }
   else if (id == 40000)
   {
      //do something
   }
   else if (id == 45000)
   {
      //do something
   }
   else
   {
      //do something else
   }
}

定数は、この例のために拡張した 16 進表記のマクロです。これは本当にバグであることが判明しましたが、デバッガーでは発見が容易ではありませんでした。何が起こったのか:

if (id == 30000)GDB を使用して (最適化なしで) コードをステップ実行しようとしていたとき、GDB が , に到達した後、毎回else ステートメントに直接ジャンプすることに気付きました。40000数値は 16 進数表記の c マクロだったので、最初は a の制限を超えていることに気づきませんでしたsigned short。これは非常に誤解を招くものであり、その解明に何時間も費やしました。とりわけ、外部ライブラリを再コンパイルし、g++ を再インストールしました。

明らかに、問題をid修正unsigned shortしました。もう 1 つの問題は、コンパイラの問題のようです。しかし、私はまだ理解していません.コードのこれらのセクションが実行中に完全にスキップされ、最適化されていないのはなぜですか? なぜそれが各ステートメントを通過しないのでif、本当の問題を特定できるのでしょうか? 何か案は?

本当にありがとう。これで最初の質問は大丈夫だと思います。

4

5 に答える 5

3

gcc からのすべての警告を有効にすると、コンパイル時にこれが発生することが通知されます。

于 2011-01-22T20:10:09.443 に答える
1

short は 16 ビット長で、その範囲は -32768 から 32767 です。したがって、40000 または 45000 になることはなく、コンパイラはデッド コードを削除します (到達することはないため)。

于 2011-01-22T20:31:22.763 に答える
1

私の結論はあなたのものと同じです。「最適化」をオンにしなくても最適化されたようです。おそらく、これらの定数述語「常に真」/「常に偽」は、コード生成ステップのどこかでコードを直接スキップするために使用されます。つまり、-O スイッチの最適化が実行されるよりも早く実行されます。推測です。

于 2011-01-22T20:14:17.247 に答える
1

GCC は優れた最適化コンパイラですが、-Werror、-Wall などでエラーおよび警告情報が有効になっている場合でも、GCC は診断コンパイルと同じレベルの情報を生成しません。コードの開発中は、バグやエラーの発見に役立つ診断コンパイラである Clang を使用することをお勧めします。Clang は GCC との互換性を意図しており、いくつかの難解な機能を除いて、Makefile の 2 つの間で CC を問題なく変更できました。

最適化コンパイラであるため、GCC はデフォルトでデッドコードの除去を有効にしていると思います。これにより、id 変数の範囲外の分岐など、コンパイラが不可能と判断したすべての分岐が削除されます。そのタイプのデッドコードの排除を無効にできる場合があります。

于 2011-01-22T20:21:41.880 に答える
1

コンパイル中に、C++ コンパイラはコードを調べて、コードのどの部分をどの順序で実行するかを決定することを思い出してください。コードの一部が実行されないとコンパイラが判断した場合、コンパイラはその部分を最適化しません。

例えば:

int i = 0;
if( i == 1) {
    printf("This will never be printed\n");
}

ここでは、if ステートメントは決して実行されないため、最適化する理由はありません。

この種のインスタンスは、次のようにコンパイルすると取得されます。

g++ -Wall mycode.c

where-Wallはすべての警告を表示することを意味しmycode.c、プロジェクト ファイルです。

実行に関しては、GDB をステップ実行すると、プログラムの現在のフローが表示されます。分岐 (if ステートメント内) が false の場合、なぜコードのそのセクションを通過するのでしょうか? if-elseif-else ステートメントで実行できる分岐は 1 つだけです。

それがあなたを助けることを願っています。

于 2011-01-22T20:27:25.003 に答える