デバッグ

初級VBA

デバッグの仕方

 ブログラムを始めたばかりの頃は、デバッグの仕方まで手が回らないというのが実情かもしれません。実際に筆者もプログラムが動かなくなって原因を突き止められなくなった時は仕方なくあきらめたりといった経験もあります。

 ただ、ある程度プログラムを組みようになるとデバックの仕方、デバッガの使い方はプログラミングをする上で必須なのだと思うようになりました。

 ちなみにデバッグとは、プログラムのミスを見つけて取り除く作業の事で、デバッガとはデバックをするための機能を備えたツールを指します。

 実はデバッガを使わなくてもデバッグすることはできます。筆者が初心者の頃よく行ったのはメッセージボックスで値を表示させてみるという事でした。筆者は独学でしたので、デバッガの使うのは敷居が高く感じており、変数の値をメッセージボックスで表示させる方法は良く使っていました。

 しかし、デバッガの機能はデバッグをする上で強力ですので、デバッガの使い方を覚えるに越したことはありません。簡単な使い方と実例を示しますので、是非マスターしてください。

VBEのデバッガ画面

デバッガはVBEの機能として備わっています。メニューから「デバッグ」を選択すると青い枠にデバッグのためのコマンドが確認できます。
 また、緑の枠には、ボタンでプログラムを進めたり、止めたり、終了したりするボタンが配置されています。
 下の赤枠部分には、イミディエイトウィンドウローカルウインドウが配置されていますが、これらが表示されていない場合は、メニューの「表示」から選択すれば表示することが出来るようになりまうす。

イミディエイトウィンドウ

 イミディエイトウィンドウは、Debug.Print というコマンドの値を表示させるためのウインドウです。デバッグ用なので、VBEを使っていない時はこの画面の表示は意味を持ちません。

プログラム中に、

   Debug.Print 変数名

と記述すると、イミディエイトウィンドウに変数の値を表示してくれます。

ローカルウインドウ

 ローカルウインドウには、そのプログラムで使われている変数オブジェクトと、その時点での値が表示されます。ブレイクポイントなどでプログラムを止めながら実行することで内部の値の変化を確認できます。

ウォッチウィンドウ

 上記の画像には表示されていませんが、その他にウォッチウインドウというのがあります。
 ウォッチウィンドウに変数をドラッグアンドドロップしておくと、その変数が実行中にどのように変化していくかを見ることができます
ウォッチウィンドウはVBEのメニューの「表示」「ウォッチウィンドウ」で表示できます。

ブレークポイントの設定

 ブレークポイントを設定すると、プログラムの実行をその位置で停止してくれます。
停止した行のコマンドは、実行される前の段階です。
 既に実行された変数の値などは、その場所にカーソルを持って行ったり、下にあるローカルウインドウなどで変数が今何が代入されているかなどを確認できます。

 ブレークポイントを設定するには、ウインドウ左のインジケーター部分をクリックします。もう一度同じ場所をクリックすれば解除されます。

 そこから再開させたいときはF5キーか、「継続」ボタン(三角ボタン)を押せばプログラムを再開します。

 ブレークポイントはいくつでもセットできますが、Dimなど変数の宣言部分や空行など、設定できない場所もあります。

ステップイン、ステップオーバー、ステップアウト

 これらの3つは、ブレークポイントなどで実行を停止した際に、再開後どのような動作で処理を進ませるかの違いで変わります。

ステップイン(F8)

 一行づつ実行します。

ステップオーバー(Shift+F8)

 途中にプロシージャの呼び出しがあった場合、そのプロシージャの内部へ進みますが、ステップオーバーでは、途中でプロシージャの呼び出しがあっても止まらずに進みます。

ステップアウト(Ctrl+Shift+F8) 

 呼び出されたプロシージャ内にいる時、そのプロシージャを最後まで実行した後に、呼び出し元へ戻ります。

実例で学ぶデバッガの使い方

 一通りの説明をしましたが、実際にやってみないと出来るようにならないのがデバッグ作業です。以下にFizzBuzzという海外の遊びを真似たプログラムを書きながらデバッガの使い方について学んでみましょう。

FizzBuzz問題

FizzBuzzとは、

  • 3で割り切れる時には”Fizz”と返す。
  • 5で割り切れる時には”Buzz”と返す。
  • 15で割り切れる時は、”FizzBuzz”と返す。
  • それ以外の時には数値を返す。

というルールを数人で順番に言っていく海外の遊びです。
今回は、これを以下のようなメッセージボックスに表示させるプログラムを書いてみます。

プログラムを書いてみる

まずは、標準モジュールを追加して、コードを書いていきます。
Module1を追加したら、プロシージャを書いていきます。

1.今回のプロシージャ名はFizzBuzzとします。
 とりあえず、1から15までのループが必要なので、カウント用の変数 i と For文を用意します。

Sub FizzBuzz()
    Dim i As Long
      For i = 1 To 15
    Next i
End Sub

2.メッセージボックスに表示させる文字列用の変数も用意しましょう。
 今回は str とします。最後にメッセージボックスで表示させるので、そのコードも書いておきます。

Sub FizzBuzz()
    Dim i As Long
    Dim str As String
        For i = 1 To 15
    Next i
    
    MsgBox str
End Sub

3.ここまでで、一応メッセージボックスが表示されるか試してみてもいいでしょう。
 まだ、文字列をセットしていないので、文字は表示されません。
 エラーが出たとしたら多分スペルミスなので間違いが無いか確認してみましょう。

4.変数 i が 15まで繰り返されてメッセージボックスに表示される仕組みを作ります。
 まずは、変数str に空文字をセットしておきます。
 これは、無くても最初は空文字となっているので結果は同じなのですが、
 空文字で初期化するという明示的な意味で書いておきます。

  str = “”

 次にFor文の中で、表示する文字列を作っていきます。
i は 1から15まで変化していくので、
  str = str & i
としてやります。str = i で繰り返すと、それまでの値が消されてしまうので15だけしか残りません。
文字列を加える時は & を使います。

こうすることで、12345,,, と iの値が文字列に追加されます。
今回は、

  1
  2
  3
  4
  5
  ,,

と表示させたいので、i の後に改行を加えます。改行は定数の vbCrLf を使います。

  str = str & i & vbCrLf

これで、改行されてメッセージボックスに表示されるはずです。
以下のコードを実行して結果を試してみましょう。

Sub FizzBuzz()
    Dim i As Long
    Dim str As String
    
    str = ""
    For i = 1 To 15
        str = str & i & vbCrLf
    Next i
    
    MsgBox str
End Sub

※For文の内部はプログラムをわかりやすくするため字下げをしましょう。

5.次は条件分岐です。「~の時は、」となるような時は If文が必要です。
 「~の時は、」が4つあるので、If、ElseIf、ElseIf、Else、、End IF という全体像になるのがわかります。
 最初の、
3で割り切れる時には”Fizz”と返す。
 を考えてみます。

 3で割り切れる時は、3で割った時の余りが0になるケースと考えます。
 今回は割り算の余りを計算する Mod が使えます。

 変数 i が 3で割り切れる時に If文が True となればいいので、

  If i Mod 3 = 0 Then

 とすれば良いでしょう。
 3で割り切れる時は、Fizz と表示させたいので i ではなく ”Fizz”とします。
 今のところは3で割り切れる時以外は数字を表示するようにしましょう。

Sub FizzBuzz()
    Dim i As Long
    Dim str As String
    
    str = ""
    For i = 1 To 15
        If i Mod 3 = 0 Then
            str = str & "Fizz" & vbCrLf
        Else
            str = str & i & vbCrLf
        End If
    Next i
    
    MsgBox str
End Sub

※ If文の内部も字下げします。

6.さて、ここまでくれば後は簡単です。
 「5で割り切れる時には”Buzz”と返す。」
 「15で割り切れる時は、”FizzBuzz”と返す。」
 これを ElseIf で加えてみます。

Sub FizzBuzz()
    Dim i As Long
    Dim str As String
    
    str = ""
    For i = 1 To 15
        If i Mod 3 = 0 Then
            str = str & "Fizz" & vbCrLf
        ElseIf i Mod 5 = 0 Then
            str = str & "Buzz" & vbCrLf
        ElseIf i Mod 15 = 0 Then
            str = str & "FizzBuzz" & vbCrLf
        Else
            str = str & i & vbCrLf
        End If
    Next i
    
    MsgBox str
End Sub

これで実行してみてください。
、、、おかしいですね。15の所で FizzBuzz と表示されていません。

デバッグ作業

7.バグを見つける
 では、VBEで●の部分をクリックしてプログラムをストップさせながら原因を見つけてみましょう。

 F5キーを押して実行してみると、黄色い矢印の部分で止まりました。
 下のローカルウインドウには、
  i が 1
  str が ””
 であることを示しています。
(ローカルウインドウが出ていない場合は、メニューの「表示」「ローカルウインドウ」としてください。)

 この時点では、まだこの行は実行されていません。
 では、F8(ステップイン)を押して、一行づつ実行されていく様子を見ていきましょう。

 i の値や strの値が変化していくのがわかると思います。

 i が15の時、どうなったでしょうか?

 一番上の、 If i Mod 3 = 0 Then で処理されていますね。
 そうです。15は、3で割り切れるため、先にこちらで処理されていたのです。

 では、どうすればこの状況を回避できるでしょうか?

 15で割り切れる処理を先に持ってくれば良さそうですね。

Sub FizzBuzz()
    Dim i As Long
    Dim str As String
    
    str = ""
    For i = 1 To 15
        If i Mod 15 = 0 Then
            str = str & "FizzBuzz" & vbCrLf
        ElseIf i Mod 3 = 0 Then
            str = str & "Fizz" & vbCrLf
        ElseIf i Mod 5 = 0 Then
            str = str & "Buzz" & vbCrLf
        Else
            str = str & i & vbCrLf
        End If
    Next i
    
    MsgBox str
End Sub

これで完成となります。
デバッガを使えば、思い込みや勘違いに気付くことができ、機械的に不具合のある箇所を突き止められます。

また、このような事を繰り返していくうちに、ミスを起こしずらいプログラムを書けるようになりますので、是非デバッガを使いこなせるようになってください。

タイトルとURLをコピーしました