連載

改訂版
プロフェッショナルVB.NETプログラミング

Chapter 02  データ型の変化

株式会社ピーデー 川俣 晶
2004/03/04


 本記事は、(株)技術評論社が発行する書籍『VB6プログラマーのための入門 Visual Basic .NET 独習講座』の一部分を許可を得て転載したものです。同書籍に関する詳しい情報については、本記事の最後に掲載しています。

 列挙型とその値

 列挙型はVB 6にも存在する機能だが、VB.NETでは挙動が変わっている。それを確かめるために、サンプル・プログラムを作成してみた。まず、VB 6で記述した例を見てみよう。

 1: Enum SampleEnumType
 2:   alpha = 0
 3:   beta = 1
 4: End Enum
 5:
 6: Private Sub dump(ByVal e As SampleEnumType)
 7:   Debug.Print e
 8: End Sub
 9:
10: Private Sub Form_Load()
11:   dump SampleEnumType.alpha
12:   dump SampleEnumType.beta
13: End Sub
リスト2-63 列挙型を使用したプログラム

 これを実行すると次のようになる。

1:  0
2:  1
リスト2-64 リスト2-63の実行結果

 それではVB.NET用に書き換えてみよう。リスト2-65がそれだ。

 1: Enum SampleEnumType
 2:   alpha = 0
 3:   beta = 1
 4: End Enum
 5:
 6: Private Sub dump(ByVal e As SampleEnumType)
 7:   Trace.WriteLine(e)
 8: End Sub
 9:
10: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
11:   dump(SampleEnumType.alpha)
12:   dump(SampleEnumType.beta)
13: End Sub
リスト2-65 リスト2-63をVB.NETで書き換えたプログラム

 これを実行すると以下のようになる。

1: alpha
2: beta
リスト2-66 リスト2-65の実行結果

 見てのとおり、VB 6では数値が表示されたが、VB.NETでは名前が表示された。VB.NETでも、内部的に列挙型は数値で処理されることに変わりはない。しかし、文字列に変換される際に、数値ではなく名前を返すような動作を行うようになっている。明示的にこの動作を行う場合は、ToString()メソッドを呼び出す。VB 6のように、数値を取り出すには、以下のようにdumpメソッドを書き換える。

6: Private Sub dump(ByVal e As SampleEnumType)
7:   Trace.WriteLine(CInt(e))
8: End Sub
リスト2-67 列挙型の値を数値で表示するように書き換えたdumpメソッド

 このように、CInt関数でキャストして整数として扱えば、数値として出力される(キャストに関しては、Option Strict(本連載Chapter 13で公開予定)を参照)。

 このほか、いくつかの列挙型に関するトピックを見てみよう。

 1: Enum SampleEnumType As Byte
 2:   alpha = 0
 3:   beta = 1
 4: End Enum
 5:
 6: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 7:   Dim s As String
 8:   For Each s In System.Enum.GetNames(GetType(SampleEnumType))
 9:     Trace.WriteLine(s)
10:   Next
11: End Sub
リスト2-68 列挙型に含まれる名前の一覧を表示するプログラム

 これを実行すると以下のようになる。

1: alpha
2: beta
リスト2-69 リスト2-68の実行結果

 リスト2-68で注目すべき点は2つある。1つは、1行目に付加されたAs Byteというデータ型指定である。これは列挙型の値を格納する整数のデータ型を指定するものである。この例なら、たかだか0と1を示すだけでよいので、Byte型で十分である。Integer型などの、より大きな表現力を持つ整数型を使う必要はない。これにより、この列挙型の配列などを確保したとき、メモリの節約になる。これは、Integer型は32bitで記憶するが、Byte型は8bitで記憶するためである。もう1つは、8行目にあるSystem.Enumクラスのインスタンスを活用していることである。このクラスには、列挙型を活用するための機能が含まれている。GetNamesメソッドは、列挙型に含まれる名前の一覧を、文字列の配列として返す機能を持っているものである。

 文字列代入によるメモリ消費量の違い

 VB 6のString型は内容を書き換えられる。しかし、VB.NETのString型は内容を書き換えられない。VB.NETでは、特別な状況を除き、文字列の加工は別の文字列型オブジェクトを作成することを意味する。しかし、同じ文字列を異なる変数に代入するような場合、String型は参照型なので、文字列オブジェクトへの参照のみが代入され、文字列が変数にコピーされるわけではない(参照型については値型と参照型のパフォーマンスの相違値型と参照型の振る舞いの相違を参照)。そこで、同じ文字列を大量に扱う場合、VB 6とVB.NETではメモリの必要量に相違が発生する。それを確かめるために、フォームにボタンを貼り付けてから、ボタンのクリックイベントに同じ文字列を大量に複製するコードを書き込んでみよう。まずはVB 6用から。

1: Private a(99999) As String
2:
3: Private Sub Command1_Click()
4:   Dim i As Long
5:   For i = 0 To 99999
6:     a(i) = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
7:   Next
8: End Sub
リスト2-70 ボタンがクリックされると大量の文字列をコピーするプログラム

 このプログラムからEXEファイルを作成し、実行してみる。そして、タスクマネージャの[プロセス]タブを利用して、メモリ使用量を調べる(Windowsのバージョンによっては使用できない場合がある)。筆者が試したときは、5584KBytes(約5.5MBytes)であった。そしてボタンを押して処理を実行させてからメモリ使用量を見ると、20520KBytes(約20MBytes)になった。つまり、この処理により、20520 - 5584 = 14936KBytes(約14.5MBytes)のメモリ使用量が増えたことになる。

 では、次にVB.NETの場合を見てみよう。

1: Private a(99999) As String
2:
3: Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
4:   Dim i As Integer
5:   For i = 0 To 99999
6:     a(i) = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
7:   Next
8:
9: End Sub
リスト2-71 リスト2-70をVB.NETで書き換えたプログラム

 このプログラムをDebugビルドで実行してみた。同じように消費量を調べたところ、13612 - 13508 = 104KBytesということになった。VB 6の場合は14936KBytesだったので、けた違いに少ないことになる。ここで使用した文字列は62文字の長さなので、これを10000個の配列に入れると、文字だけで、62文字 * 10000個 * 2Bytes = 1240000Bytes = 12400KBytes(約12MBytes)必要となる(2Bytesは、文字がUnicodeのUTF-16で保存されることによるもの。これらの文字は1文字2Bytesになる)。VB 6は、ほぼこれぐらいのメモリを消費したが、VB.NETで記述した場合にはこれよりはるかに少ない量しか消費していない。これは、文字列本体は1個しか確保されず、代入はすべて参照の代入として処理されていることによる。これにより、メモリの消費量が変わるだけでなく、処理速度にも影響を及ぼす場合があるだろう。文字列を大量に扱う場合には知っておくとメリットがある特徴である。

 デフォルトのデータ型

 VB 6には、「Def」の3文字で始まるステートメントがあり、変数のデフォルトのデータ型を指定することができる。例えばDefIntは、変数のデフォルトのデータ型が整数型(Integer)であることを示す。「DefInt A」と記述したソース上で、文字「A」で始まる変数名を使用すると、それはIntegerであると見なされる。かつて筆者が使っていた1979年発売のパソコン、PC-8001に搭載されていたMicrosoft製のN-BASICにもあったものだから、非常に古く伝統ある由緒正しい機能といえる。リスト2-72は、それを実際に記述したサンプル・ソースである。

1: DefInt A
2: DefSng B
3:
4: Private Sub Form_Load()
5:   a = 1.2
6:   b = 1.2
7:   Debug.Print a, b
8: End Sub
リスト2-72 “Def〜”のステートメントを使用したプログラム

 これを実行すると以下のような結果が得られる。

1             1.2
リスト2-73 リスト2-72の実行結果

 5行目で初めて出現する変数aは、1行目のDefInt Aの効能により、Integer型と見なされる。そのため、1.2を代入しても整数に丸められ、1という値が格納される。一方、6行目の変数bは、2行目のDefSngの効能によりSingle型と見なされ、小数点以下の値も保存される。

 これに相当するソースは、VB.NETでは記述できない。というのは、Defで始まるDefIntなどのステートメントは一切存在しないためである。無理に書けばリスト2-74のようになる。

1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2:   Dim a As Integer, b As Single
3:   a = 1.2
4:   b = 1.2
5:   Trace.WriteLine(a & ", " & b)
6: End Sub
リスト2-74 リスト2-72に似せたVB.NETのプログラム

 これを実行すると以下のようになる。

1, 1.2
リスト2-75 リスト2-74の実行結果

 見てのとおり、変数ごとにデータ型を明示するように記述するよりほかに方法はない。しかし、この世の中で、先頭の1文字が共通なら同じデータ型などという都合のよいソースがそうそうあるわけがなく、Defで始まるステートメントは現実には使えない機能だったと考えた方がよいだろう。これはあくまで、可読性を落としてもソースを短くしなければならなかった初期のパソコンでのみ利用価値のあった機能といえる。事実、むかしの8bitパソコンでは、処理速度の向上と省メモリのために、プログラム先頭で「DEFINT A-Z」などと記述することも多かった。だが、それはすでに過去の話である。End of Article

VB6プログラマーのための入門 Visual Basic .NET 独習講座』

 本記事は、(株)技術評論社が発行する書籍『VB6 プログラマーのための 入門 Visual Basic .NET 独習講座』から
許可を得て転載したものです。

【本連載と書籍の関係について 】
 この書籍は、本フォーラムで連載した「連載 プロフェッショナルVB.NETプログラミング」を大幅に加筆修正し、発行されたものです。技術評論社、および著者である川俣晶氏のご好意により、書籍の内容を本フォーラムの連載記事として掲載させていただけることになりました。

技術評論社の解説ページ

ご注文はこちらから


 INDEX
  [連載] 改訂版 プロフェッショナルVB.NETプログラミング
  Chapter 02 データ型の変化
    1.プリミティブ型のエイリアス/ VariantとObject/新しい整数型と整数型が表現できる数値範囲の拡大
    2.通貨、日付、構造体の変化/配列添え字の下限/配列のサイズ変更
    3.変数の初期化/配列の初期化/配列の次元数の変更/配列を作成するさまざまな方法/配列の共変性
    4.固定長文字列/構造体宣言/値型と参照型のパフォーマンスの相違
    5.値型と参照型の振る舞いの相違/日付と時刻の変更/日付時刻の書式化
  6.列挙型とその値/文字列代入によるメモリ消費量の違い/デフォルトのデータ型

「改訂版 プロフェッショナルVB.NETプログラミング 」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH