この記事では、最適化されたコードをより適切にデバッグできるように設定するコンパイラ スイッチについて説明します。
Visual Studio 2022 バージョン 17.14 以降では、最適化されたコードの速度を維持しながら、最適化されたコードを最適化されていない状態でコンパイルされたかのようにデバッグできる、より優れたエクスペリエンスが提供されます。 詳細については、「C++ 動的デバッグ (プレビュー)を参照してください。
注
表示されるダイアログ ボックスとメニュー コマンドは、アクティブな設定やエディションによってヘルプで説明されているものとは異なる場合があります。 設定を変更するには、[ツール] メニュー [設定のインポートとエクスポート] を選択します。 詳細については、「すべての設定をリセットする」を参照してください。
注
/Zo (最適化されたデバッグの強化) コンパイラ オプション (Visual Studio Update 3 で導入) では、最適化されたコード (/Od コンパイラ オプションを使用してビルドされていないプロジェクト) のデバッグ情報が豊富に生成されます。 /O オプション (コードの最適化)を参照してください。 これには、ローカル変数とインライン関数のデバッグのサポートが強化されています。
/Zo コンパイラ オプションを使用すると、エディット アンド コンティニュー は無効になります。
コンパイラは、コードを最適化すると、命令の位置を変更して再構成します。 これにより、コンパイルされたコードの効率が向上します。 この再配置により、デバッガーは一連の命令に対応するソース コードを常に識別できるわけではありません。
最適化は次の影響を受ける可能性があります。
オプティマイザーは、ローカル変数を削除したり、デバッガーが認識できない場所に移動したりできます。
関数内の位置。これは、オプティマイザーがコード ブロックをマージするときに変更されます。
オプティマイザーによって 2 つの関数がマージされた場合、呼び出し履歴上のフレームに対して、間違った関数名が表示される場合があります。
ただし、すべてのフレームにシンボルがあると仮定すると、呼び出し履歴に表示されるフレームはほぼ常に正しいです。 スタックの破損がある場合、アセンブリ言語で記述された関数がある場合、または呼び出し履歴にシンボルが一致しないオペレーティング システム フレームがある場合、呼び出し履歴のフレームは間違っています。
グローバル変数と静的変数は常に正しく表示されます。 構造レイアウトも同じになります。 構造体へのポインターがあり、ポインターの値が正しい場合、構造体のすべてのメンバー変数に正しい値が表示されます。
これらの制限があるため、可能であれば、最適化されていないバージョンのプログラムを使用してデバッグする必要があります。 既定では、最適化は C++ プログラムのデバッグ構成でオフになり、リリース構成で有効になります。
ただし、バグは、プログラムの最適化されたバージョンでのみ表示される場合があります。 その場合は、最適化されたコードをデバッグする必要があります。
デバッグ ビルド構成で最適化を有効にするには
新しいプロジェクトを作成するときに、
Win32 Debug
ターゲットを選択します。 プログラムが完全にデバッグされ、Win32 Release
ターゲットをビルドする準備ができるまで、Win32 Debug
ターゲットを使用します。 コンパイラは、Win32 Debug
ターゲットを最適化しません。ソリューション エクスプローラーでプロジェクトを選択します。
[表示] メニューの [プロパティ ページ] をクリックします。
[プロパティ ページ ] ダイアログ ボックスで、[構成] ドロップダウン リストで
Debug
が選択されていることを確認します。左側のフォルダー ビューで、C/C++ フォルダーを選択します。
C++ フォルダーで、
Optimization
を選択します。右側のプロパティの一覧で、
Optimization
を見つけます。 その横の設定は、おそらく /Od)
Disabled (
と表示されます。 他のオプション (Minimum Size``(
/O1)
、Maximum Speed``(
/O2)
、Full Optimization``(
/Ox)
、またはCustom
) のいずれかを選択します。Optimization
のCustom
オプションを選択した場合、プロパティ リストに表示されるその他のプロパティのオプションを設定できるようになりました。プロジェクトのプロパティ ページの [構成プロパティ]、[C/C++]、[コマンド ライン] ノードを選択し、[追加オプション] テキスト ボックスに
(
/Zo)
を追加します。警告
/Zo
を追加すると、[エディット コンティニュ] が無効になります。最適化されたコードをデバッグするときは、逆アセンブル ウィンドウを使用して、作成および実行される手順を確認します。 ブレークポイントを設定するときは、ブレークポイントが命令と共に移動する可能性があることを知る必要があります。 たとえば、次のコードを考えてみましょう。
for (x=0; x<10; x++)
この行にブレークポイントを設定したとします。 ブレークポイントが 10 回ヒットすることが予想される場合がありますが、コードが最適化されている場合、ブレークポイントは 1 回だけヒットします。 これは、最初の命令で x
の値が 0 に設定されるためです。 コンパイラは、これを 1 回だけ行う必要があることを認識し、ループから移動します。 このとき、ブレークポイントもこの命令とともに移動します。 x
を比較してインクリメントする命令はループ内に残ります。 逆アセンブル ウィンドウを表示すると、ステップ ユニット が自動的に Instruction に設定され、より詳細な制御が可能になります。これは、最適化されたコードをステップ 実行するときに便利です。