C言語でプログラムを書いていると、コンパイルは通るのに実行結果が想定と異なる、あるいは「セグメンテーション違反(Segmentation fault)」でプログラムがクラッシュしてしまうといった問題に直面することが多々あります。このようなプログラムの誤りや実行時エラーの原因を特定し、修正するために欠かせないのがデバッガです。
本記事では、C言語における代表的なデバッガである「gdb(GNU Debugger)」の基本的な使い方について解説します。gdbを活用すれば、プログラムの実行を任意の場所で一時停止させたり、変数の値を一行ずつ確認したりすることができ、バグの早期発見・解決に大きく役立ちます。
gdbとは?C言語開発に欠かせないデバッグツール
gdb(GNU Debugger)は、GNUプロジェクトによって開発された強力なデバッガで、C言語やC++を含む多くのプログラミング言語に対応しています。プログラムの内部動作を可視化し、バグの原因を突き止めるための様々な機能を提供しています。
LinuxLinux [リナックス / ライナックス]オープンソースのOSカーネルやUNIX系環境では標準的に利用されており、コマンドラインから操作するのが基本です。最初はとっつきにくいかもしれませんが、基本コマンドを覚えるだけで劇的にデバッグ効率が向上します。
gdbを使うための準備:C言語コードのコンパイル方法
gdbでC言語のプログラムをデバッグするには、コンパイル時にデバッグ情報を含める必要があります。これには、gccコンパイラの -g オプションを使用します。
gcc -g -O0 target.c -o target-g:プログラムにデバッグ情報を追加し、gdbでソースコードと紐付けたデバッグを可能にします。(※#defineなどのマクロ定義もデバッガ内で参照したい場合は、より詳細な情報を含む-g3を指定すると便利です)-O0(一般的に「オーゼロ」と読みます):コンパイラによる最適化を無効にします。最適化が有効だと、ソースコードの行と実際の実行処理が一致しなくなり、デバッグが困難になるため指定することをおすすめします。
gdbの基本的な使い方:起動と終了
gdbの起動方法
コンパイルして生成された実行ファイル(例:target)を引数にして、gdbコマンドを実行します。
gdb ./target起動すると、(gdb) というプロンプトが表示され、コマンド入力待ち状態になります。
gdbの終了方法
gdbを終了するには、quit コマンド(または省略形の q)を入力します。
(gdb) quitC言語デバッグでよく使うgdbの基本コマンド一覧
gdbには数多くのコマンドがありますが、日常的なデバッグで使うのは以下のコマンドが中心です。各コマンドには省略形が用意されており、入力の手間を省くことができます。
| コマンド | 省略形 | 説明 |
|---|---|---|
run | r | プログラムの実行を開始する |
break | b | ブレークポイント(一時停止位置)を設定する |
next | n | 次の行を1行実行する(関数の中には入らない) |
step | s | 次の行を1行実行する(関数の中に入る) |
continue | c | 次のブレークポイントまでプログラムの実行を再開する |
print | p | 変数や式の現在の値を表示する |
list | l | 現在実行中の周辺のソースコードを表示する |
info locals | - | 現在のスコープにあるローカル変数の一覧と値を表示する |
※ info locals には公式な1文字の短縮形はありませんが、gdbはコマンドが一意に特定できる範囲での部分入力を受け付けるため、実用上は i lo が標準的な省略形として広く使われています。
実践チュートリアル:gdbを使ったC言語プログラムのデバッグ手法
ここでは、意図した通りの結果にならない単純なプログラムを例に、実際にgdbを使ってバグを見つける流れを体験してみましょう。
デバッグ用サンプルプログラム(C言語)
以下の calc.c は、1から5までの整数の合計(本来は15)を計算して表示するプログラムですが、変数の初期化に関する誤りを含んでいます。
#include <stdio.h>
int main() { int sum; int i;
for (i = 1; i <= 5; i++) { sum = sum + i; }
printf("1から5の合計は: %d\n", sum); return 0;}コンパイルして実行してみます。
gcc -g -O0 calc.c -o calc./calc環境によっては、実行結果が 15 にならず、デタラメな数値が表示されることがあります。この原因をgdbで探ります。
なお、このような単純な未初期化変数の問題は、gdbだけでなくコンパイラの警告によって発見できる場合もあります。開発時には
-Wall -Wextraなどの警告オプションも併用すると効果的です。
gdbを用いたバグ特定の手順
1. gdbを起動する
gdb ./calc2. ブレークポイントを設定する
今回は sum = sum + i; が実行される直前の状態を確認したいので、関数内の特定の行(ここでは8行目)にブレークポイントを張ります。
(gdb) b 8Breakpoint 1 at 0x...: file calc.c, line 8.※ 実際の表示は環境によって異なります。
※ b 8 のように、ソースファイルの行番号を指定してブレークポイントを設定することも可能です。
3. プログラムを実行する
(gdb) runStarting program: /path/to/calc
Breakpoint 1, main () at calc.c:88 sum = sum + i;ブレークポイントで実行が一時停止します。
4. 変数の値を確認する
この時点での変数 sum と i の値を見てみましょう。
(gdb) p sum$1 = <不定な値>(gdb) p i$2 = 1※ <不定な値> は説明上の表記です。実際のGDBでは環境によって異なる数値などが表示される場合があります。
ここでバグの原因が判明します。i にはループの初期化によって 1 が入っていますが、このプログラムでは sum が初期化されていません。C言語では、初期化されていないローカル変数は「不定値」を持つため、その値を読み取って計算に使用すると動作は未定義になります。したがって環境によって異なる値が表示される場合があります。
sum が初期化されないまま計算に使用されていることが、今回のバグの原因であると分かります。このようにして、想定と実際の挙動のズレや変数の異常な状態を見つけるのがデバッグの基本です。
5. gdbを終了してコードを修正する
(gdb) quitcalc.c の変数宣言を int sum = 0; に修正して再コンパイル・実行すれば、正しい結果が得られます。
gdbのより高度な使い方(条件付きブレークポイント)
ループ処理の中で、特定の条件を満たした時だけプログラムを止めたい場合は、条件付きブレークポイントが便利です。
(gdb) break 8 if i == 4これにより、指定した行(ここでは8行目)に到達したとき、i == 4 が成立する場合だけ停止します。ループ回数が多いプログラムのデバッグで非常に重宝します。
まとめ:gdbをマスターしてC言語のデバッグ効率を上げよう
C言語のプログラミングにおいて、gdbは強力な武器となります。最初はコマンド操作に慣れないかもしれませんが、 「-gをつけてコンパイル」「runで実行」「breakで止める」「printで値を確認」「next/stepで進める」 という基本サイクルを覚えるだけで、バグ解決のスピードは飛躍的に向上します。
printf関数を使って変数を出力する「printfデバッグ」も有効ですが、複雑なプログラムやセグメンテーション違反などの実行時エラーの原因究明にも、gdbは非常に役立ちます。ぜひ本記事を参考に、C言語開発でのgdb活用を始めてみてください。
以上で本記事の解説を終わります。
よいITライフを!
人気記事
- 1
- 2
- 3
- 4
- 5
思考の整理というテーマを、実務ですぐに使える具体的な「技術」として落とし込んだ一冊です。