初心者向けに噛み砕いて、実際に手を動かして学べるように例題・練習問題付きで詳しく説明します。
ざっくり要点
- 「どこで変数を宣言するか」で、その変数が使える範囲(スコープ)が決まります。
- プロシージャ(Sub / Function)内で宣言するとそのプロシージャだけで使える(ローカル)。
- プロシージャの外(モジュールの先頭)で宣言すると、そのモジュール内のすべてのプロシージャで使える(モジュールレベル)。
1. まずは「プロシージャ内で宣言した変数(ローカル変数)」
説明:Dim をプロシージャの中で書くと、その変数は「そのプロシージャ内だけ」で有効になります。別のプロシージャからは見えません。
例:
Option Explicit
Sub TestA()
Dim x As Integer
x = 5
MsgBox "TestA の x = " & x ' → 5
End Sub
Sub TestB()
MsgBox "TestB の x = " & x ' エラー:変数 x は定義されていない(Option Explicit があるとコンパイルエラー)
End Sub
VBポイント:
Option Explicitを使うと、宣言していない変数はエラーになります(タイプミスや勘違いを防げるので必須レベルでおすすめ)。
2. 「モジュール(プロシージャの外)で宣言した変数(モジュールレベル)」
説明:モジュールの先頭に Dim(または Private)で宣言すると、そのモジュール内の全てのプロシージャから同じ変数を使えます。状態を共有したいときに使います。
例:
Option Explicit
Dim counter As Integer ' モジュールレベル
Sub Init()
counter = 10
MsgBox "Init: counter = " & counter ' → 10
End Sub
Sub AddFive()
counter = counter + 5
MsgBox "AddFive: counter = " & counter ' Init 実行後に実行すると → 15
End Sub
VBポイント:
- 同じモジュール内のプロシージャ同士で値を受け渡すのに便利。だが使い方を誤ると「どこで値が変わったか分からない」バグの原因にもなります。
3. ローカル変数とモジュール変数が同名の場合(シャドーイング)
説明:モジュールの外で宣言した num と、あるプロシージャ内で同名 num を再び Dim すると、プロシージャ内の num が優先(ローカルが勝つ)で、モジュール変数は別物として扱われます。
例:
Option Explicit
Dim num As Integer ' モジュール変数
Sub A()
num = 10 ' モジュール変数に 10 が入る
End Sub
Sub B()
Dim num As Integer ' ローカル変数(ここではモジュール変数とは別)
num = 3
MsgBox "B の num = " & num ' → 3(ローカル)
End Sub
Sub C()
num = num + 5
MsgBox "C の num = " & num ' A を実行していれば → 15(A で 10、C で +5)
End Sub
VBポイント:
- 同名を使うと混乱するので、モジュール変数にはプレフィックスをつける(例:
m_counter)など、命名ルールを決めよう。
4. モジュールを超えて共有したいとき(別モジュール/全プロジェクトで使いたいとき)
- そのモジュールだけでなくプロジェクト全体(他のモジュール)で使いたい場合は、
Publicを使います。例:Public gValue As Integerを標準モジュールのトップに置けば、どのモジュールのプロシージャからも参照可能です。
(参考ページではモジュールレベルまで触れていますが、Publicの取り扱いもよく使われます。)
注意:
Public変数は便利だが、どこからでも書き換えられるため、大規模コードでは副作用管理が難しくなります。
5. 実際に試すときの手順(Excel でのやり方)
- Excel を開く →
Alt + F11で VBA エディタを開く。 - メニューの「挿入」→「標準モジュール」を追加。
- そこに上のサンプルコードを貼り付ける。
F5か、プロシージャ名を選んでRunで実行。メッセージボックスやイミディエイトウィンドウ(Ctrl+G)で結果を確認する。
(Option Explicitをオンにしておくと安全です:モジュールの先頭にOption Explicitを書く。)
6. よくある落とし穴(初心者がハマりやすい点)
- 変数の宣言漏れ(タイプミスで別の変数を作ってしまう)→
Option Explicitを必ず使う。 - 「どのプロシージャが変数を変えたのか分からない」→ モジュールレベル/Public 変数をむやみに増やさない。代わりに引数や戻り値でデータを渡す設計を検討。
- 同名で別変数が存在(ローカルとモジュールで同名)→ 意図せぬ挙動になる。命名規則で回避。
- グローバル変数を多用するとバグの追跡が困難に。
7. 練習問題
問題1(基本)
A モジュールに以下を書いて、順に RunInit → RunInc を実行してどう表示されるか答えよ。
Option Explicit
Dim v As Integer
Sub RunInit()
v = 2
MsgBox "RunInit: v = " & v
End Sub
Sub RunInc()
v = v + 3
MsgBox "RunInc: v = " & v
End Sub
VB解答1:RunInit → 「RunInit: v = 2」, その後 RunInc → 「RunInc: v = 5」。
問題2(シャドーイング確認)
次を順に A, B, C 実行。各 MsgBox が何を表示するか。
Option Explicit
Dim num As Integer
Sub A()
num = 7
End Sub
Sub B()
Dim num As Integer
num = 1
MsgBox "B: num = " & num
End Sub
Sub C()
MsgBox "C: num = " & num
End Sub
VB解答2:B → 「B: num = 1」, C → 「C: num = 7」(A を先に実行している前提。A を実行していなければ C は 0)。
問題3(少し応用)
別モジュール(Module1 と Module2)に分けて Public g As Integer を宣言するとどうなるか試してみよう(Module1: Public g As Integer、Module1 Sub が g = 100 をセット、Module2 から MsgBox で表示)。結果:Module2 からも g が 100 と表示される(モジュールを跨いで共有される)。
まとめ(実践的なアドバイス)
- まずは
Option Explicitを全モジュールに書く。 - できるだけ「値は渡す(引数/戻り値)」で済ませ、モジュール/Public 変数は必要最小限に。
- モジュール変数を使うなら
m_やmod_などプレフィックスで区別すると読みやすい。 - コードが大きくなったら、作用域(スコープ)を意識してモジュール分割・命名規則を徹底すること。

