#14 変数の型宣言をする・しない?

結論
処理スピードの面からも適切な変数の型宣言を行うべきであり、これはループカウンタ変数についても同様である。

VBAの言語仕様というのは非常に優しくできていて、コードの中で使用する変数や定数は取りたててデータ型を気にしなくても宣言さえしておけばエラーとはなりません。

  Option Explicit

  Sub test2()
    Dim i,  j

    i = 12.525
    j = 999999999
  
  End Sub
しかも「Dim i」のように型指定なしに宣言された変数は自動的に"なんでもOK"のバリアント型(Variant)にしてくれますので、上のコードのようにいきなり小数を代入しても、大きな値を代入しても実行時でさえエラーとなりません。
※もし、「Dim i As Integer, j As Integer」とすると、整数型(Integer)に小数を代入したり、その範囲(-32,768〜32,767)を越える値を代入した時点で実行時エラーとなります。

さらに、先頭行にある「Option Explicit」を消してしまえば、「Dim i, j」の宣言行でさえ無くても、コンパイルおよび実行時ともにエラーなく動作してしまいます。
※ただし変数の宣言が面倒だからとこれを消してしまうのは"絶対"にやめましょう!。変数名のスペルミスでさえ許してくれるので後でとんでもないことになりかねません。

このように大変"親切"(言い方を換えればかなり"ラフ")なVBAですが、それに甘んじて書かれたコードはそれなりにデメリットも被らなければなりません。まず次の表をご覧ください。これはそれぞれのデータ型の変数1つがどれくらいのメモリ領域を使っているかを示したものです。
データ型 宣言 メモリ領域のサイズ
バイト型 Byte 1 バイト
整数型 Integer 2 バイト
長整数型 Long 4 バイト
単精度浮動小数点数型 Single 4 バイト
倍精度浮動小数点数型 Double 8 バイト
通貨型 Currency 8 バイト
バリアント型 Variant 16 バイト

もし、本来ならバイト型でよい 1〜255 の範囲の値しかとらないデータに対してバリアント型の変数を割り当てたとしたら、15バイトも余分にメモリを消費することになります。

  Dim Data As Byte・・・・・・バイト型を明示的に宣言
  Dim Data            ・・・・・・暗黙的にバリアント型となる

しかしこの型宣言の問題はそれだけではないようです。パソコンというハードウェアやOSというものは整数型あるいは長整数型を扱うのがもっとも効率的なようにできていますので、たとえそれが"1.0"というような簡単な数値であっても、それが倍精度浮動小数点数型として扱われていればそれだけで処理のパフォーマンスが落ちてしまいます。

とはいえ、それが実際にどの程度処理時間に影響を与えるのか、現実的な値は確認したことがありません。そこでここでは、変数の型宣言をした場合とそうでない場合、言い方を換えれば、そのデータ値に適した型宣言をした場合とバリアント型として使う場合とで処理時間の比較を行ってみたいと思います。

テストとして次のようなコードを実行して、その処理時間を測定してみます。なお、参考までに、ループで囲まれた代入式の部分をすべて削除し、単純にループを5000×5000回処理するだけの時間も測定してみました。


  Dim i, j, dummy
  Dim iintLoop As Integer, jintLoop As Integer, intdummy As Integer
  Dim ilngLoop As Long, jlngLoop As Long, lngdummy As Long
  Dim isngLoop As Single, jsngLoop As Single, sngdummy As Single
  Dim idblLoop As Double, jdblLoop As Double, dbldummy As Double
  Dim icurLoop As Currency, jcurLoop As Currency, curdummy As Currency
  Const cvarLoopMax As Integer = 5000
  
  ts_Watch "開始", True
  
  For i = 1 To cvarLoopMax
    For j = 1 To cvarLoopMax
      dummy = j・・・・・・この部分を除いた場合もテスト(以下も同様)
    Next j
  Next i
  ts_Watch "テスト1"

  For iintLoop = 1 To cvarLoopMax
    For jintLoop = 1 To cvarLoopMax
      intdummy = jintLoop
    Next jintLoop
  Next iintLoop
  ts_Watch "テスト2"

  For ilngLoop = 1 To cvarLoopMax
    For jlngLoop = 1 To cvarLoopMax
      lngdummy = jlngLoop
    Next jlngLoop
  Next ilngLoop
  ts_Watch "テスト3"

  For isngLoop = 1 To cvarLoopMax
    For jsngLoop = 1 To cvarLoopMax
      sngdummy = jsngLoop
    Next jsngLoop
  Next isngLoop
  ts_Watch "テスト4"

  For idblLoop = 1 To cvarLoopMax
    For jdblLoop = 1 To cvarLoopMax
      dbldummy = jdblLoop
    Next jdblLoop
  Next idblLoop
  ts_Watch "テスト5"
  
  For icurLoop = 1 To cvarLoopMax
    For jcurLoop = 1 To cvarLoopMax
      curdummy = jcurLoop
    Next jcurLoop
  Next icurLoop
  ts_Watch "テスト6"

そして、テスト結果はつぎのようなものになりました。なお時間の単位は"秒"です。


ループで変数代入
を行う場合
代入式を除いた
ループだけの場合
テスト1 バリアント型 18.09 9.31
テスト2 整数型 12.64 6.31
テスト3 長整数型 11.23 6.32
テスト4 単精度浮動小数点数型 15.44 9.25
テスト5 倍精度浮動小数点数型 16.09 10.55
テスト6 通貨型 14.50 7.61

やはり、バリアント型というのは遅い!ということが確認できました。おおむねメモリ領域のサイズが大きくなると処理時間も大きくなっているようです。変数の型宣言をしていない場合には暗黙的にバリアント型になってしまいますので、処理スピードの面からもやはり適切な変数の型宣言を行うべきであるといえます。この結果の中で、特にコーディングする際に注意しなければいけないと感じたのは、代入式を除いたループだけの実行結果です。ここでの代入式の左辺にある変数は、実際の処理ではそれぞれ何らかの意味を持っているはずですから、そのデータがもし小数点を扱う場合であれば浮動小数点数型(SingleまたはDouble)を使わざるを得ないわけですが、ループのカウンタとして使う変数についてはふだん軽く考えがちではないでしょうか?。ところがこの結果を見ると、ループのカウンタ変数の型宣言もいかに処理時間に大きな影響を与えるかが判ると思います。もちろんループ処理の内容によっては浮動小数点数型を使う必要がある場合もあるでしょうが、ループカウンタ変数もきちんと型宣言をすべきという結論になると思います。

| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved