デバッグの基礎
すべてのプログラマー――そう、プロでさえも――はバグのあるコードを書いてしまいます。初心者とエキスパートの違いは、ミスを犯すかどうかではなく、どれだけ早くそのミスを見つけて修正できるかにあります。このレッスンでは、毎日役立つデバッグのスキルを学びます。
1. 3種類のエラー
(1) 1.1 コンパイル時のエラー
これらは、プログラムが実行される前にコンパイラによって検出されます。
int x = 5
cout << x << endl; // ❌ Missing semicolon!
表示内容: コンパイラは、ファイル名と行番号を含むエラーメッセージを出力します。
解決方法: エラーメッセージを注意深く読みましょう。通常、問題の具体的な箇所や、本来どのような動作が期待されているかが明記されています。
(2) 1.2 実行時エラー
これらはプログラムの実行中に発生します。プログラムがクラッシュしたり、予期しない動作をしたりする可能性があります。
int arr[5] = {1,2,3,4,5};
cout << arr[100] << endl; // ❌ Array index out of bounds
int x = 10 / 0; // ❌ Division by zero
表示される内容: クラッシュ、「セグメンテーションフォールト」、または不正な出力。
解決方法: コードを逐一確認してください。配列の範囲外へのアクセス、ゼロ除算、およびNULLポインタのチェックを行ってください。
(3) 1.3 論理的誤り
プログラムはクラッシュすることなく動作しますが、間違った結果を出力してしまいます。こうした不具合は、最も発見が難しいものです。
// This should convert Celsius to Fahrenheit
double celsius = 100;
double fahrenheit = celsius * 9/5 + 32; // ✅ Correct: 212
double wrong = celsius * 9/5 - 32; // ❌ Wrong: 148
表示内容: プログラムは「動作」はするものの、間違った答えを出します。
解決方法: ここでデバッグ技術が真価を発揮します。
2. cout によるデバッグ手法
最も簡単なデバッグ手法:すべてを出力する。
#include iostream
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
std::cout << "[DEBUG] i=" << i << ", result=" << result << std::endl;
}
return result;
}
int main() {
std::cout << factorial(5) << std::endl;
return 0;
}
出力:
[DEBUG] i=1, result=1
[DEBUG] i=2, result=2
[DEBUG] i=3, result=6
[DEBUG] i=4, result=24
[DEBUG] i=5, result=120
120
[DEBUG] というプレフィックスを付けておくと、後で簡単に見つけ出して削除できます。本番環境のコードにデバッグ出力を残したままにしないでください。
3. IDEのデバッガの使用
VS Codeのデバッガーでは、以下の操作が可能です:
- ブレークポイントを設定する — 行番号をクリックすると、その行で実行が一時停止します
- ステップオーバー — 1行ずつ実行する
- Step into — 関数に入り、内部で何が起きているかを確認する
- 変数の監視 — 値がリアルタイムでどのように変化するかを確認する
(1) VS Code でのデバッガーの設定
- C/C++ Extension Pack(デバッグツールを含む)をインストールします。
.cppファイルを開きますF5を押してデバッグを開始します- 「C++ (GDB/LLDB)」環境を選択します
- 行番号をクリックしてブレークポイントを設定します
F10を押してコードを順に実行する
4. コンパイラの警告
警告はエラーではありませんが、コンパイラが「これは怪しい」と伝えているものです。警告はエラーとして扱うようにしてください。
// Compile with: g++ -Wall -Wextra -Werror program.cpp
| フラグ | 効果 |
|---|---|
-Wall |
最も一般的な警告を有効にする |
-Wextra |
追加の警告を有効にする |
-Werror |
すべての警告をエラーとして扱う |
(1) ▶ サンプル:1:バグを見つけよう(難易度 ⭐⭐)
#include iostream
int main() {
int x; // Bug 1: uninitialized variable
std::cout << x; // Output is unpredictable!
int arr[5];
arr[5] = 10; // Bug 2: array out of bounds
for (int i = 0; i <= 5; i++) { // Bug 3: should be i < 5
arr[i] = i;
}
return 0;
}
-Wall -Wextra -Werror を使ってコンパイルすると、上記の3つのバグをすべて検出できます!
▶ サンプル 1: debugging basicsデモ (難易度 ⭐)
#include <iostream>
int main() {
// debugging basicsの
std::cout << "debugging basicsをびましょう!" << std::endl;
return 0;
}
❓ よくある質問
std::endl(フラッシュを行う)または std::flush を使用して、即時出力を強制してください。📖 まとめ
- 3種類のエラー:コンパイル時(最も簡単)、実行時(中程度)、論理(最も難しい)
- 問題を早期に発見するために、
-Wall -Wextra -Werrorを使用してコンパイルしてください coutデバッグ手法:重要なポイントで変数の値を出力する- IDEのデバッガーを使えば、ブレークポイントを設定したり、コードをステップ実行したりできます
- よくあるバグ:初期化されていない変数、オフ・バイ・ワンエラー、セミコロン書き忘れ
📝 練習問題
- 初心者(難易度 ⭐): 以下のバグのあるプログラムを修正してください(5つのバグが含まれています):
#include iostream
int main() {
int x
cout << "Enter a number: ";
cin >> x
if (x = 5) {
std::cout << "You entered 5" << std::endl;
}
int arr[3] = {1,2,3};
std::cout << arr[3] << std::endl;
return 0
}
-
中級(難易度 ⭐⭐): 各種類のエラー(コンパイル時エラー、実行時エラー、論理エラー)を意図的に含めたプログラムを作成してください。その後、それらを一つずつ修正し、どのような変更を加えたかを記録してください。
-
上級(難易度 ⭐⭐⭐): 再帰関数を実装し、VS Codeのデバッガーを使用して、各再帰呼び出しをステップ実行してください。各レベルにおけるコールスタックの変化と変数の値を確認してください。デバッガーのスクリーンショットを撮影してください。



