次の例では、デバッグが必要な SQUARES という名前のプログラムを説明します。このプログラムはコンパイルされ、コンパイラまたはリンカのいずれからも診断メッセージを出力せずにリンクされたものです。ただし、このプログラムの算術式には、論理エラーが含まれています。
コンパイラによって割り当てられた行番号は、この例にも追加されており、説明文が参照しているソース行を識別できるようになっています。
PROGRAM SQUARES
INTEGER INARR(10), OUTARR(10), I, K
!Read the input array from the data file.
OPEN(UNIT=8, FILE='datafile.dat', STATUS='OLD')
READ(8,*,END=5) N, (INARR(I), I=1,N)
5 CLOSE (UNIT=8)
!Square all nonzero elements and store in OUTARR.
K = 0
DO I = 1, N
IF (INARR(I) .NE.0) THEN
K = K + 1 !add this line
OUTARR(K) = INARR(I)**2
ENDIF
END DO
!Print the squared output values. Then stop.
PRINT 20, N
20 FORMAT (' Total number of elements read is',I4)
PRINT 30, K
0 FORMAT (' Number of nonzero elements is',I4)
DO, I=1,K
PRINT 40, I, OUTARR(K)
40 FORMAT(' Element', I4, 'Has value',I6)
END DO
END PROGRAM SQUARES
この SQUARES プログラムは次の関数を実行します。
データファイルから一連の整数番号を読み取り、これらの番号を配列 INARR に保存します。datafile.dat ファイルには、整数値 4、3、2、5、および 2 を含む 1 つのレコードが含まれています。最初の番号は、この数値の後に続くデータ項目の数を示します。
各非ゼロ整数値の二乗の値を別の配列 OUTARR にコピーするループを実行します。
元のシーケンスに含まれている非ゼロ要素の数および各要素の二乗の値を出力します。
この例では、(-check bounds コマンドライン・オプションを設定して) プログラムが配列の上下限を確認せずに実行されていることを仮定します。配列の上下限を確認して実行した場合、ランタイム・エラー・メッセージが表示されます。
SQUARES を実行すると、データファイルに含まれた非ゼロ要素の数にかかわらず、次の出力を表示します。
squares
Number of nonzero elements is 0
OUTARR の現在のインデックスを示す変数 K が 9 行目から 13 行目までのループでインクリメントされなかったため、論理エラーが発生します。K = K + 1 文を 11 行目の前に追加する必要があります。
次の例では、デバッグ・セッションの開始方法および文字セル・インターフェイスを使用して、上記のサンプル・プログラムからエラーを検出する方法を説明します。コールアウトの右に示されている番号は、後述のプログラム解説の番号です。
ifort -g -o squares squares.f90 (1)
idb squares (2)
Linux Application Debugger for xx-bit applications, Version x.x, Build xxxx
object file name: squares
reading symbolic information ... done
(idb) list 1,9 (3)
1 PROGRAM SQUARES
2 INTEGER INARR(20), OUTARR(20)
3 C !Read the input array from the data file.
> 4 OPEN(UNIT=8, FILE='datafile.dat', STATUS='OLD')
5 READ(8,*,END=5) N, (INARR(I), I=1,N)
6 5 CLOSE (UNIT=8)
7 C !Square all nonzero elements and store in OUTARR.
8 K = 0
9 DO 10 I = 1, N
(idb) stop at 8 (4)
[#1: stop at "squares.f90":8]
(idb) run (5)
[1] stopped at ["squares.f90":4 0x120001a88]
> 8 K = 0
(idb) step (6)
stopped at [squares:9 0x120001a90]
9 DO 10 I = 1, N
(idb) print n, k (7)
4 0
(idb) step (8)
stopped at [squares:10 0x120001ab0]]
10 IF(INARR(I) .NE.0) THEN
(idb) s
stopped at [squares:11 0x1200011acc]
11 OUTARR(K) = INARR(I)**2
(idb) print i, k (9)
1 0
(idb) assign k = 1 (10)
(idb) watch variable k (11)
[#2: watch variable (write) k 0x1400002c0 to 0x1400002c3 ]
(idb) cont (12)
Number of nonzero elements is 1
Element 1 has value 4
Process has exited with status 0
(idb) quit (13)
% vi squares.f90 (14)
.
.
.
10: IF(INARR(I) .NE.0) THEN
11: K = K + 1
12: OUTARR(K) = INARR(I)**2
13: ENDIF
.
.
.
% ifort -g -o squares squares.f90 (15)
% idb squares
Welcome to the idb Debugger Version x.x-xx
Reading symbolic information ...done
(idb) when at 12 {print k} (16)
[#1: when at "squares.f90":12 { print K} ]
(idb) run (17)
[1] when [squares:12 0x120001ae0]
1
[1] when [squares:12 0x120001ae0]
2
[1] when [squares:12 0x120001ae0]
3
[1] when [squares:12 0x120001ae0]
4
Number of nonzero elements is 4
Element 1 has value 9
Element 2 has value 4
Element 3 has value 25
Element 4 has value 4
Process has exited with status 0
(idb) quit (18)
%
コマンドラインの -g オプションは、SQUARES に関するシンボル情報を、デバッガのオブジェクト・ファイルに出力します。また、このオプションはコンパイラによって処理される多くの最適化を無効にすることで、実行コードがプログラムのソースコードと一致するようにします。
シェルコマンド idb squares は、デバッガを実行します。画面にデバッガに関する情報とデバッガ・プロンプト (idb) が表示されます。このコマンドでは、squares という名前の実行プログラムが指定されています。デバッガ・プロンプトが表示された後は、デバッガコマンドを入力することができます。idb squares コマンドを実行すると、メイン・プログラム・ユニット (この例では、プログラム SQUARES となります) を開始する前で停止します。
list 1,9 コマンドは、1 行目から 9 行目までを出力します。
stop at 8 コマンドは、8 行目にブレークポイント (1) を設定します。
run コマンドは、プログラムの実行を開始します。プログラムは、8 行目に設定された最初のブレークポイントで停止するため、プログラムの実行が完了する前に、変数 N および K を確認することができます。
step コマンドは、プログラムの実行を 9 行目に移動します。step コマンドは、実行コードと関係のないソース行を無視します。またデフォルトでは、デバッガは実行を停止するソース行を識別します。サブプログラムへ移動しないようにするには、step コマンドの代わりに next コマンドを使用します。
print n, k コマンドは、変数 N および K の現在の値を表示します。これらの値は、この時点では正しい値です。
step コマンドを 2 回実行することで、プログラムの実行をループ (9 行目から 11 行目) まで移動します。ここでは、INARR に含まれたすべての非ゼロ要素の値をそれぞれ二乗して、OUTARR にコピーします。一部のコマンドは、省略することができます。この例では、step コマンドを s コマンドとして省略しています。
print i, k コマンドは、変数 I および K の現在の値を表示します。予測された変数 I の値は 1 です。しかし、変数 K の値には、予測された値である 1 の代わりに 0 が含まれています。このエラーを修正するには、11 行目のコードを実行する前に、K の値をインクリメントする必要があります。
assign コマンドは、K の値に 1 を割り当てます。
watch variable k コマンドは、変数 K の値が変化するたびに起動されるウォッチポイントを設定します。元のプログラムでは、変数 K の値が変更されないため (これは、プログラムのエラーです)、このウォッチポイントは起動されません。
このパッチをテストするには、cont コマンド (continue コマンドの省略コマンドです) を使用して、現在の場所からプログラムの実行を再開します。プログラムの出力は、最初の配列要素のみが正常に動作していること表示します。プログラムのエラーによって K の値が変化しないため、ウォッチポイント (watch variable k コマンド) が発生しません。プログラムの実行が完了したことを示す idb メッセージ "Process has exited with status 0" が表示されます。
quit コマンドは制御をシェルに戻すため、ソースファイルを修正して、プログラムの再コンパイルおよび再リンクを行うことができます。
vi シェルコマンドは、テキストエディタを実行します。テキストエディタで、ソースファイルの 10 行目の後に K = K + 1 文を追加してください。(コンパイラによって割り当てられた行番号は、この例にも追加されています。)
修正したプログラムをコンパイルおよびリンクします。idb squares シェルコマンドにより、修正したプログラムに対してデバッガを開始し、問題が修正されたことを確認することができます。
when at 12 {print k} コマンドは、ループの各反復における変数 K の値を通知します。
run コマンドは、実行を開始します。
表示された変数 K の値で、プログラムが正常に動作していることを確認します。
quit コマンドは、デバッグ・セッションを終了し、制御をシェルに戻します。