VBA技術解説
値渡し(ByVal)、参照渡し(ByRef)について

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
公開日:2013年5月以前 最終更新日:2022-06-22

値渡し(ByVal)、参照渡し(ByRef)について


ByValが値渡し、ByRefが参照渡しです。
ここまでは、どこにでも書いてあります。
しかし、なんとなく理解できるけど、なんとなく理解できない・・・


結局のところ実際の活用がなかなか出来ない事が多いようです。
使用例を通じて、理解して下さい。


ByVal(値渡し)とByRef(参照渡し)

ByVal:値渡し

変数の中のデータを渡すもので、呼出側の変数は影響を受けません。
つまり、値渡しでは、呼出し先で引数の値を変更しても、呼出し元の引数は変更されません。

マクロ VBA サンプル画像

変数の値を求めて、その値を渡します。
呼出し先から戻ってきても、変数の値は変化しません。


ByRef:参照渡し

変数そのものを渡すもので、呼出側の変数が影響を受けます。
つまり、参照渡しでは、呼び出し先で引数の値を変更すると、呼び出し元の引数も変更されます。

VBA マクロ 値渡し ByVal 参照渡し ByRef

変数そのものを渡します。
呼出し先で引数の値を変更した場合は、その変更後の引数が呼出し元の変数に入ります。

ただし、呼出元で変数ではなく、関数や数式を引数にした場合や、変数を括弧()で囲んだ場合は値渡し(ByVal)になります。
以下の記述は、呼出し先がByRef(参照渡し)でもByVal(値渡し)になります。
本来は必要のない括弧()を付けている場合
Call 呼び出し先((変数))
呼び出し先 (変数)
変数を評価して値を求めてから、その値を渡すことになります。
VBAでの括弧()の使い方、括弧が必要な場合
・基本文型 ・VBAにおける括弧() ・VBAにおける半角空白の意味 ・戻り値を他の用途に使う時 ・括弧()の使い方の基本文型 ・Callを省略しなければ全て括弧が必要になる ・最後に一言

関数や数式の場合
Call 呼び出し先(関数(変数))
Call 呼び出し先(変数+変数)
関数や数式なので、そのままでは渡すことはできないので、値評価後に値を渡します。


普通の変数(プリミティブ型)の場合

Sub sample1()
  Dim i, j
  i = 1
  j = 1
  Call sub1(i, j)
  MsgBox i
  MsgBox j
End Sub
Sub sub1(arg1, arg2)
  arg1 = arg1 + 1
  arg2 = arg2 + 2
End Sub

上記のsample1を実行すると、2,3の順にメッセージ表示されます。
ByValもByRef指定していないので、省略時のByRefとなっています。
この場合、ByRefなので参照渡しとなり、Call元のプロシージャーの引数も変更されます。

Sub sample2()
  Dim i, j
  i = 1
  j = 1
  Call sub2(i, j)
  MsgBox i
  MsgBox j
End Sub
Sub sub2(ByVal arg1, ByVal arg2)
  arg1 = arg1 + 1
  arg2 = arg2 + 2
End Sub

上記のsample2を実行すると、1,1の順にメッセージ表示されます。
ByValを指定しているので値渡しとなっています。
この場合、Call元のプロシージャーの引数は変更されません。

普通の変数(プリミティブ型)は理解しやすいと思います。


オブジェクト変数の場合

オブジェクト変数については、以下を参照してください。
オブジェクト変数とは何か|VBA技術解説
・そもそも変数とは何か ・変数の入れ物としての大きさは ・オブジェクト変数にオブジェクトは入っていない ・オブジェクト変数のメモリアドレス ・Is演算子によるオブジェクトの比較 ・TypeOf演算子 ・オブジェクト変数を使う時の注意点 ・オブジェクト変数の最後に

引数にオブジェクトを指定した場合に、勘違いしている場合が多いです。

Sub sample()
  Dim MyRange As Range
  Set MyRange = Range("A1")
  Call sample2(MyRange)
End Sub

Sub sample2(ByVal MyRange As Range)
  MyRange.Value = 1
End Sub

上記の結果は、A1セルに1が入ります。
当然ですよね。
つまり、ByValで渡されたオブジェクトに変更を加えれば、呼出し元でもオブジェクトは変更されています。

Range以外の他のオブジェクトでも同じことです。
では、オブジェクトの場合、ByValとByRefの違いは何でしょうか?

オブジェクト変数がByValの場合

Sub sample()
  Dim MyRange As Range
  Set MyRange = Range("A1")
  Call sample2(MyRange)
  MyRange.Value = 2
End Sub

Sub sample2(ByVal MyRange As Range)
  MyRange.Value = 1
  Set MyRange = Range("A2")
End Sub

上記の結果は、A1セルに2が入るだけです。
sample2での
Set MyRange = Range("A2")
これは、ByValなので呼出し元に影響を与えません。


オブジェクト変数がByRefの場合

Sub sample()
  Dim MyRange As Range
  Set MyRange = Range("A1")
  Call sample2(MyRange)
  MyRange.Value = 2
End Sub

Sub sample2(ByRef MyRange As Range)
  MyRange.Value = 1
  Set MyRange = Range("A2")
End Sub

この結果は、A1セルに1、A2セルに2が入ります。
sample2での
Set MyRange = Range("A2")
この変更が、呼出し元に返されています。

ここでは、とても単純な例にしましたが、
オブジェクトを引数に使う場合の参考にして下さい。


サイト内のByVal,ByRefの記事

Variant仮引数のByRefとByValの挙動違い
ツイッターで出したVBAのお題です。Variant型は、どんなデータ型も入れることができてしまいます。具体的なデータ型の代わりに使用することで、より柔軟にVBA記述ができるようになります。ただしこの便利さゆえに、逆に注意しなければならない挙動もあります。
オブジェクトのByRef、ByVal、Variant
ツイッターで出題した問題です。オブジェクトを引数にした場合の、ByRef、ByValの違いと、仮引数にVariantを指定した場合の動作違いを問う問題です。出題ツイート 【VBA問題】 Submain() Range("A1")=1 DimaAsRange:Seta=Range("A1…




同じテーマ「マクロVBA技術解説」の記事

WorksheetFunctionについて
RangeとCellsの深遠
Offset、Resizeを使いこなそう
値渡し(ByVal)、参照渡し(ByRef)について
最終行・最終列の取得方法(End,CurrentRegion,SpecialCells,UsedRange)
ユーザー定義関数の作り方
セルの値について(Value,Value2,Text)
Excelのバージョンを判断して「名前を付けて保存」
空白セルを正しく判定する方法(IsEmpty,IsError,HasFormula)
空白セルを正しく判定する方法2
Rangeオブジェクト.Valueの省略について


新着記事NEW ・・・新着記事一覧を見る

Gemini CLIの徹底解説:AIをターミナルから使いこなす|生成AI活用研究(2025-07-03)
Gemini CLIとPowerShellでVBAerのAI活用を加速する実践ガイド|生成AI活用研究(2025-07-02)
「Gemini CLI」によるExcel自動化フレームワーク:実践ガイド|生成AI活用研究(2025-07-01)
AI(Gemini)とエクセル数式対決 その3|生成AI活用研究(2025-06-24)
不合理の砦|AIが計算を終えた場所から、人間の価値が始まる|生成AI活用研究(2025-06-23)
生成AIはExcelの複雑な数式を書けるのか?|AIとの対話から学ぶ協業のリアル|生成AI活用研究(2025-06-22)
日時データから日付ごとの集計(UNIQUE,SUMIFS,GROUPBY)|エクセル雑感(2025-06-20)
AI時代の働き方革命:オンリーワン戦略 ― 属人化で搾取されない労働者に|生成AI活用研究(2025-06-20)
VBA開発の標準化を実現する共通プロンプトのすすめ|生成AI活用研究(2025-06-14)
生成AIと100本ノック 29本目:画像の挿入|生成AI活用研究(6月13日)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.変数宣言のDimとデータ型|VBA入門
3.繰り返し処理(For Next)|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.RangeとCellsの使い方|VBA入門
6.FILTER関数(範囲をフィルター処理)|エクセル入門
7.セルのクリア(Clear,ClearContents)|VBA入門
8.メッセージボックス(MsgBox関数)|VBA入門
9.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
10.マクロとは?VBAとは?VBAでできること|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
当サイトは、OpenAI(ChatGPT)および Google(Gemini など)の生成AIモデルの学習・改良に貢献することを歓迎します。
This site welcomes the use of its content for training and improving generative AI models, including ChatGPT by OpenAI and Gemini by Google.



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ