19

GCCがif(0)ブロック内のコードを削除しないようにするにはどうすればよいですか?

Visual Studioを使用する場合、デバッグ手法の1つは、次のようなコードをプログラムに配置することです。

if (0)
    do_some_debug_printing_and_checking();

次に、ブレークポイントに到達したら、do_some_debug_printing_and_checking()行をクリックし、[set next statement]を選択して、強制的に実行します。

gcc / gdbをバックエンドとして使用すると、GCCがif(0)ステートメント内からコードを削除するだけなので、「setnextステートメント」は機能しなくなります。

もちろん、最適化を無効にするために-O0フラグを使用しています。また、デッドコードの除去を明示的に無効にするために-fno-dce -fno-tree-dceフラグを試しましたが、効果はありません。if (0)の内容がバイナリファイルに存在しないため、setnextを使用できませんそれに飛び込むステートメント。

if(0)コンテンツの削除を無効にするようにgccに指示する良い方法はありますか?

編集:

「追加の変数」の回避策に感謝しますが、私が気に入らない点が2つあります。

  1. それはまだ余分なコード行です
  2. リリースバージョンをビルドするときに自動的に最適化されないので、それらのデバッグ機能を無効にします。確かに#ifdef-sを使用できますが、それはさらに余分な行です。

本当に、GCCにそのデッドコードを保持させるオプションは絶対にありませんか?

4

2 に答える 2

12

最も簡単な方法は、外部リンケージを持つ変数 (たとえば) にチェックを依存させることです。

例えば

extern bool debug;
if (debug)
    do_some_debug_printing_and_checking();

名前空間スコープのどこか:

bool debug = false;
于 2012-07-01T11:19:31.500 に答える
8

これを行うために gcc コンパイラ フラグに依存することはありません。コンパイラ フラグは、gcc のバージョン間で変更される可能性があり、コンパイラ間で変更されます。Visual C++ で同じコードを 6 か月でデバッグする必要があることに気付くかもしれません...

@CharlesBailey は、変数を使用してこれを行う方法について良い提案をしていexternます。変数をモジュール全体に公開したり、静的ストレージに保持したりする必要がない代替手段の 1 つを次に示します。

ステートメントvolatileのスコープで一時変数を宣言します。if

if (volatile bool dbg = false)
{
  do_some_debug_printing_and_checking();
}

これにより、一時変数の範囲が非常に狭くなります。修飾子により、volatileコンパイラは変数について何も仮定したり、分岐を最適化したりできなくなります。

覚えておくべきことの 1 つは、変数は常にスタックに割り当てられ、関数が終了するまでスタックに保持されるということです。このアプローチとアプローチの両方がextern機能するはずですが、わずかに異なる (そしておそらく無視できる) トレードオフがあります。

この問題を解決するためにマクロを使用する場合は、コードを本番環境にリリースするときに一時変数を簡単に無効にすることができます。

#ifndef IS_DEBUGGING
#  define IS_DEBUGGING 0
#endif

#if IS_DEBUGGING
#  define TMP_DBG_FLAG volatile bool dbg_flag = false
#else
#  define TMP_DBG_FLAG false
#endif

次に、ifステートメントを次のように宣言します。

if ( TMP_DBG_FLAG )
{
  do_some_debug_printing_and_checking();
}

IS_DEBUGGING を 1 に定義すると、ローカル変数が作成され、volatile と宣言され、保持されます。IS_DEBUGGING を 0 に定義すると、マクロは定数falseに展開され、コンパイラは分岐を最適化します。externアプローチについても、非常によく似たことができます。

この数行の追加コードは、TMP_DBG_FLAG を使用する回数とは関係ありません。コードは、大量のifdefs を使用するよりもはるかに読みやすくなります。マクロは (値を追加することで) 少し安全にすることができますが__LINE__、これには 3 つのマクロが必要であり、おそらく必要ありません。

#if IS_DEBUGGING
// paste symbols 'x' and 'y' together
#  define TMP_DBG_FLAG_SYMCAT0(x,y) x ## y

// need one level of indirection to expand __LINE__...
#  define TMP_DBG_FLAG_SYMCAT(x,y) TMP_DBG_FLAG_SYMCAT0(x,y)

#  define TMP_DBG_FLAG volatile bool TMP_DBG_FLAG_SYMCAT(dbg_flag_,__LINE__) = false
#else
#  define TMP_DBG_FLAG false
#endif
于 2012-07-01T19:38:31.627 に答える