月刊プログラム!
VisualBasic For Excel

Vol_08
2001.MAY.30

Presented by kouta_y
感想等は掲示板、苦情はメールへ。

にこちゃん
今回は構造体についてです。
これは、覚えるとかなり便利なんでマスターしちゃいましょう。


※訂正(2002.08.19)
メモリの配置のされ方について説明に誤りがありました。(現在訂正しています。ごめんなさい)

宣言

まず構造体の宣言の仕方です。
宣言する場所はグローバル領域(プロージャの外)です。

' 構造体の宣言は Type ステートメントを使う
Type MyStruct
    Name As String
    Age  As Integer
End Type
TypeEnd Typeの中に、変数を宣言するように、構造体のメンバ(要素)を宣言します。

構造体とは複数(または単体)のメンバ(要素)を持ち、ユーザー定義型とも呼ばれます。
変数とは違います。
「型」そのものを宣言していると考えてください。
上の例では「MyStruct」という構造体を宣言しました。
この構造体を実際に使用する場合は、
Dim Status As MyStruct
とし、Status 変数を MyStruct 型として宣言します。

では、どうやって使うのか?
上の例の場合、MyStructは2つのメンバを持っています。
「Name」と「Age」です。
実際にこれらのメンバにアクセスする場合は「Statusの中のName」とか「Statusの中のAge」といった考えでオーケーです。
では次に、この構造体を使ったサンプルコードを見てみましょう。

' モジュールレベル(グローバル領域)で宣言
' プロージャレベルでは宣言出来ない


' 構造体の宣言(ユーザー定義型とも言う)
Type MyStruct
  Name As String   ' As から型の位置を揃えると見やすいカモ
  Age  As Integer
End Type



Sub Sample()

' MyStruct型の変数の宣言
Dim Status As MyStruct

'値の代入
Status.Name = "たろ"
Status.Age = 22

'シートに反映
Cells(1, 1).Value = "名前は"
Cells(2, 1).Value = "歳は"
Cells(1, 2).Value = Status.Name
Cells(2, 2).Value = Status.Age

End Sub

実行結果


はい。こんな感じですね。
これ書いてる現在は筆者は22歳です。
若いです。
関係ありませんね。


構造体あれこれ

構造体もマスターすれば、かなり強力な武器になります。
と同時に、後々に大きなプログラムを作っていくうちに必須なものとなりえます。
かなり便利なものなので、覚えておきましょう。


メモリの配置

構造体のメンバは配列と同じく、メモリ内へ順番に割り当てられます。
例えば、

Type MyStruct
    aaa As Integer
    bbb As Byte
    ccc As Long
    ddd As String
    eee As Boolean
End Type

という構造体を宣言したのなら、メモリへの配置は、


という感じになります。
宣言したメンバが順番に配置されている点に注意してください。
さらにこれを証明付けるコードを組んでみます。


Sub Sample()
Dim a As MyStruct

' アドレスとメンバの型の領域を表示
Debug.Print VarPtr(a.aaa); Len(a.aaa)
Debug.Print VarPtr(a.bbb); Len(a.bbb)
Debug.Print VarPtr(a.ccc); Len(a.ccc)
Debug.Print VarPtr(a.ddd); Len(a.ddd)
Debug.Print VarPtr(a.eee); Len(a.eee)

End Sub

Debug.Printとは、イミディエイトウィンドウへ処理結果を表示できる便利なデバッグの技です。
イミディエイトウィンドウは「表示(V)」メニューから「イミディエイトウィンドウ(I)」を選びます。
VarPtr関数については以前もやりました。変数のアドレスを返すVBの隠し関数です。
実行結果

6485332 2
6485334 1
6485336 4
6485340 0
6485344 2

上のメモリマップの「A1」番地を6485332番地と考えれば、上で示したメモリ配置は正しいと証明できました。

あれ?メンバdddの領域が0だけど・・・?

えーと、これは文字列型だからです。
Len関数では、文字列型の型サイズを求めることはできません。
Len関数に文字列型変数を渡すと、型サイズではなく文字の長さを調べてしまうからです。
今回はこのメンバに文字列の代入はしてませんので、0でいいのです。

んで、文字列型の型サイズというのは、今のWin32と呼ばれるOSでは32ビット、つまり4バイトとなります。
これはポインタの型サイズと同じです。
この辺の知識は少し上級者向けですので、ここでは詳しい説明は省きます。


※訂正
上記の説明ですが、Win32での構造体の場合、メモリへの配置のされ方は順番に配置されるとは限らず、メンバの型により配置のされ方が異なります
メンバの型によるとは、構造体の場合、一番サイズの大きいメンバの型のバイト境界に配置します。
上記の例の場合、Long型もしくはString型のサイズ(4バイト)が一番大きいので、4バイト境界でメモリへ配置されます。
(実行結果の数値をよくよくみると、ちゃんとそうなっていました・・・)
しかし、構造体自体のサイズは、その「埋め」のサイズは省かれますし、考え方としては一見正しいですが、説明に不備がありました。
すみません。


終わり

構造体。如何でしたでしょう。
最後のメモリ配置のされかたなどは、少し蛇足でしたが、大体基本はこんなとこです。
あと、メンバには配列、さらに構造体(構造体の中にまた構造体)といった宣言もできます。
いろいろ試してみてください。