構造体 構造体のサイズ Marshal.SizeOf メソッド 整数型等型のサイズが定義されて居る構造体の場合 Marshal.SizeOf メソッドを使う事に依り型のサイズ ( バイト数 ) を取得する事が出来る 引数に値やオブジェクトを直接指定するか typeof や GetType で取得した型情報を渡す事に依り 其の型のサイズを取得する事が出来る 下記のプログラムを実行する事に依り Marshal.SizeOf メソッドに依るサイズの取得を検証して観る Imports System.Runtime.InteropServices Visual Basic Public Class MarshalSizeOf Private Sub lstvalue_selectedindexchanged(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles lstvalue.selectedindexchanged Dim N As Integer = lstvalue.selectedindex Select Case N Case 0 MessageBox.Show(Marshal.SizeOf(16)) Case 1 MessageBox.Show(Marshal.SizeOf(3L)) Case 2 MessageBox.Show(Marshal.SizeOf(1.414F)) Case 3 MessageBox.Show(Marshal.SizeOf(3.14)) Case 5 MessageBox.Show(Marshal.SizeOf(16%)) -1-
Case 6 MessageBox.Show(Marshal.SizeOf(3&)) Case 7 MessageBox.Show(Marshal.SizeOf(1.414!)) Case 8 MessageBox.Show(Marshal.SizeOf(3.14#)) End Select End Sub Private Sub lsttype_selectedindexchanged(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles lsttype.selectedindexchanged Dim N As Integer = lsttype.selectedindex Try Select Case N Case 0 MessageBox.Show(Marshal.SizeOf(GetType(Integer))) Case 1 MessageBox.Show(Marshal.SizeOf(GetType(Long))) Case 2 MessageBox.Show(Marshal.SizeOf(GetType(Single))) Case 3 MessageBox.Show(Marshal.SizeOf(GetType(Double))) Case 4 MessageBox.Show(Marshal.SizeOf(GetType(IntPtr))) Case 5 MessageBox.Show(Marshal.SizeOf(GetType(DateTime))) Case 6 MessageBox.Show(Marshal.SizeOf(GetType(DateTimeOffset))) Case 7 MessageBox.Show(Marshal.SizeOf(GetType(TimeSpan))) Case 8 MessageBox.Show(Marshal.SizeOf(GetType(String))) Case 9 MessageBox.Show(Marshal.SizeOf(GetType(Object))) End Select Catch ex As Exception MessageBox.Show(ex.Message, " 例外 ", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Sub End Class using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace MarshalSizeOf -2-
public partial class MarshalSizeOf : Form public MarshalSizeOf() InitializeComponent(); private void lstvalue_selectedindexchanged(object sender, EventArgs e) int n = lstvalue.selectedindex; switch (n) case 0: MessageBox.Show(Marshal.SizeOf(16).ToString()); break; case 1: MessageBox.Show(Marshal.SizeOf(3L).ToString()); break; case 2: MessageBox.Show(Marshal.SizeOf(1.414F).ToString()); break; case 3: MessageBox.Show(Marshal.SizeOf(3.14).ToString()); break; private void lsttype_selectedindexchanged(object sender, EventArgs e) int n = lsttype.selectedindex; try switch (n) case 0: MessageBox.Show(Marshal.SizeOf(typeof(int)).ToString()); break; case 1: MessageBox.Show(Marshal.SizeOf(typeof(long)).ToString()); break; case 2: MessageBox.Show(Marshal.SizeOf(typeof(float)).ToString()); break; case 3: MessageBox.Show(Marshal.SizeOf(typeof(double)).ToString()); break; case 4: MessageBox.Show(Marshal.SizeOf(typeof(IntPtr)).ToString()); break; case 5: MessageBox.Show(Marshal.SizeOf(typeof(DateTime)).ToString()); break; case 6: MessageBox.Show(Marshal.SizeOf(typeof(DateTimeOffset)).ToString()); break; case 7: MessageBox.Show(Marshal.SizeOf(typeof(TimeSpan)).ToString()); break; -3-
case 8: MessageBox.Show(Marshal.SizeOf(typeof(string)).ToString()); break; case 9: MessageBox.Show(Marshal.SizeOf(typeof(object)).ToString()); break; catch (Exception ex) MessageBox.Show(ex.Message, " 例外 ", MessageBoxButtons.OK, MessageBoxIcon.Error); 実行結果を下記に示す Visual Basic リテラル 16 4 16 4 3L 8 3L 8 1.414F 4 1.414F 4 3.14 8 3.14 8 データ型 Integer 4 int 4 Long 8 long 8 Single 4 float 4 Double 8 doublr 8 IntPtr 4 IntPtr 4 DateTime 例外 DateTime 例外 DateTimeOffset 例外 DateTimeOffset 例外 TimeSpan 8 TimeSpan 8 String 例外 string 例外 Object 例外 object 例外 IntPtr は実行環境に依ってサイズが変わる 32 ビット環境では 4 64 ビット環境では 8 が返される 上記の実行結果は 32 ビット環境での物で有る IntrPtr のサイズは IntPtr.Size プロパティに依っても取得する事が出来る IntPtr の値を利用して実行環境が 32 ビットか 64 ビットか判別する事も出来る 猶 何の様な型でも Marshal.SizeOf でサイズを取得する事が出来る訳では無い 例えば DateTime 等 アンマネージコードに渡す際のマーシャリング方法が定義されて居ない型の場合はサイズを取得出来ない 型のサイズが取得出来ない場合 Marshal.SizeOf メソッドは ArgumentException をスローする DateTime の他 DateTimeOffset string や object 等の参照型の物もサイズが取得出来ない 構造体のサイズ 構造体の場合では StructLayout 属性で LayoutKind.Sequential 又は LayoutKind.Explicit が指定されて居れば Marshal.SizeOf メソッドで構造体のサイズを取得する事が出来る -4-
Imports System Imports System.Runtime.InteropServices <StructLayout(LayoutKind.Sequential)> _ Structure Point Dim X As Integer Dim Y As Integer Visual Basic <StructLayout(LayoutKind.Explicit)> _ Structure ARGB <FieldOffset(0)> Dim Value As UInteger <FieldOffset(0)> Dim B As Byte <FieldOffset(1)> Dim G As Byte <FieldOffset(2)> Dim R As Byte <FieldOffset(3)> Dim A As Byte Class Sample Shared Sub Main() Console.WriteLine("SizeOf(0) = 1", GetType(Point), Marshal.SizeOf(GetType(Point))) Console.WriteLine("SizeOf(0) = 1", GetType(ARGB), Marshal.SizeOf(GetType(ARGB))) End Sub End Class [StructLayout(LayoutKind.Sequential)] struct Point int X; int Y; [StructLayout(LayoutKind.Explicit)] struct ARGB [FieldOffset(0)] uint Value; [FieldOffset(0)] byte B; [FieldOffset(1)] byte G; [FieldOffset(2)] byte R; [FieldOffset(3)] byte A; class Sample static void Main() -5-
Console.WriteLine("SizeOf(0) = 1", typeof(point), Marshal.SizeOf(typeof(Point))); Console.WriteLine("SizeOf(0) = 1", typeof(argb), Marshal.SizeOf(typeof(ARGB))); 実行結果を下記に示す SizeOf(Point) = 8 SizeOf(ARGB) = 4 亦.NET Framework 4.5.1 以降では Marshal.SizeOf<T> メソッドが用意されて居る typeof や GetType で型情報を指定する代わりに型パラメータ T を指定する丈で型のサイズが取得出来る様に成る Imports System Imports System.Runtime.InteropServices <StructLayout(LayoutKind.Sequential)> _ Structure Point Dim X As Integer Dim Y As Integer Visual Basic Class Sample Shared Sub Main() Console.WriteLine("SizeOf(Of Integer) = 0", Marshal.SizeOf(Of Integer)()) Console.WriteLine("SizeOf(Of Point) = 0", Marshal.SizeOf(Of Point)()) End Sub End Class [StructLayout(LayoutKind.Sequential)] struct Point int X; int Y; class Sample static void Main() Console.WriteLine("SizeOf<int> = 0", Marshal.SizeOf<int>()); Console.WriteLine("SizeOf<Point> = 0", Marshal.SizeOf<Point>()); -6-
実行結果を下記に示す SizeOf<int> = 8 SizeOf<Point> = 4 sizeof では sizeof に依っても型のサイズを取得する事が出来る sizeof は int や bool 等の組み込み型に対して使用する事が出来 定義済みのサイズを返す 亦 参照型のメンバを含まない構造体に対して使用する事も出来るが 其の場合は unsafe コンテキスト内で使用する必要が有る struct Point int X; int Y; class Sample static void Main() Console.WriteLine("sizeof(int) = 0", sizeof(int)); Console.WriteLine("sizeof(long) = 0", sizeof(long)); unsafe Console.WriteLine("sizeof(Point) = 0", sizeof(point)); 実行結果を下記に示す sizeof(int) = 4 sizeof(long) = 8 sizeof(point) = 8 Marshal.SizeOf と sizeof の違い 型に依っては Marshal.SizeOf と sizeof で異なる結果と成る場合が有る 例えば bool 型では次の様に異なる結果を返す Marshal.SizeOf と sizeof -7-
class Sample static void Main() Console.WriteLine("Marshal.SizeOf(typeof(bool)) = 0", Marshal.SizeOf(typeof(bool))); Console.WriteLine("sizeof(bool) = 0", sizeof(bool)); 実行結果を下記に示す Marshal.SizeOf(typeof(bool)) = 4 sizeof(bool) = 1 此れは Marshal.SizeOf がアンマネージ API 呼び出し時にマーシャリングされる際のサイズを返すのに対し sizeof はマネージドコード上でのサイズを返すと謂う違いが有る為で有る マネージドコードでは bool 型は 1 バイトとされている為 sizeof(bool) は 1 を返す 一方 アンマネージ API 呼び出しに際して bool 型は Win32 BOOL 型にマーシャリングされる 此の BOOL 型は typedef int BOOL;(=4 バイト符号付き整数 ) とされて居る為 Marshal.SizeOf(typeof(bool)) は 4 を返す アラインメント (Pack) サイズ (Size) Marshal.SizeOf 及び sizeof は構造体のアラインメントに応じた結果を返す 次の例では StructLayout 属性の Pack パラメータを指定して構造体のアラインメントを変更して居る Imports System.Runtime.InteropServices Visual Basic ' デフォルトのアラインメント (4 バイト ) Structure S1 Dim F1 As Byte Dim F2 As Integer ' 1 バイトアラインメント <StructLayout(LayoutKind.Sequential, Pack:=1)> _ Structure S2 Dim F1 As Byte ' 1 バイト目に配置される Dim F2 As Integer ' 2~5 バイト目に配置される ' 2 バイトアラインメント <StructLayout(LayoutKind.Sequential, Pack:=2)> _ Structure S3 Dim F1 As Byte ' 1 バイト目に配置される Dim F2 As Integer ' 3~6 バイト目に配置される ' 2 バイトアラインメント <StructLayout(LayoutKind.Sequential, Pack:=4)> _ -8-
Structure S4 Dim F1 As Byte ' 1 バイト目に配置される Dim F2 As Integer ' 5~8 バイト目に配置される Module alignment Sub Main() Console.WriteLine("Marshal.SizeOf(typeof(S1)) = 0", Marshal.SizeOf(GetType(S1))) Console.WriteLine("Marshal.SizeOf(typeof(S2)) = 0", Marshal.SizeOf(GetType(S2))) Console.WriteLine("Marshal.SizeOf(typeof(S3)) = 0", Marshal.SizeOf(GetType(S3))) Console.WriteLine("Marshal.SizeOf(typeof(S4)) = 0", Marshal.SizeOf(GetType(S4))) Console.ReadLine() End Sub End Module using System.Collections.Generic; using System.Text; namespace alignment // デフォルトのアラインメント (4 バイト ) struct S1 byte F1; int F2; // 1 バイトアラインメント [StructLayout(LayoutKind.Sequential, Pack = 1)] struct S2 byte F1; // 1 バイト目に配置される int F2; // 2~5 バイト目に配置される // 2 バイトアラインメント [StructLayout(LayoutKind.Sequential, Pack = 2)] struct S3 byte F1; // 1 バイト目に配置される int F2; // 3~6 バイト目に配置される // 4 バイトアラインメント [StructLayout(LayoutKind.Sequential, Pack = 4)] struct S4-9-
byte F1; // 1 バイト目に配置される int F2; // 5~8 バイト目に配置される class alignment static void Main(string[] args) Console.WriteLine("Marshal.SizeOf(typeof(S1)) = 0", Marshal.SizeOf(typeof(S1))); Console.WriteLine("Marshal.SizeOf(typeof(S2)) = 0", Marshal.SizeOf(typeof(S2))); Console.WriteLine("Marshal.SizeOf(typeof(S3)) = 0", Marshal.SizeOf(typeof(S3))); Console.WriteLine("Marshal.SizeOf(typeof(S4)) = 0", Marshal.SizeOf(typeof(S4))); Console.WriteLine(); unsafe Console.WriteLine("sizeof(typeof(S1)) = 0", sizeof(s1)); Console.WriteLine("sizeof(typeof(S2)) = 0", sizeof(s2)); Console.WriteLine("sizeof(typeof(S3)) = 0", sizeof(s3)); Console.WriteLine("sizeof(typeof(S4)) = 0", sizeof(s4)); Console.ReadLine(); 実行結果を下記に示す (Visual Basic は上半分丈 ) 同様に Size パラメータを指定して構造体のサイズを指定した場合も其れに応じた結果と成る Visual Basic Imports System.Runtime.InteropServices -10-
' 1 バイトアラインメント <StructLayout(LayoutKind.Sequential, Pack:=1)> _ Structure S1 Dim F1 As Byte Dim F2 As Integer ' 1 バイトアラインメントで 8 バイト分確保する <StructLayout(LayoutKind.Sequential, Pack:=2, Size:=8)> _ Structure S2 Dim F1 As Byte Dim F2 As Integer ' 1 バイトアラインメントで 16 バイト分確保する <StructLayout(LayoutKind.Sequential, Pack:=4, Size:=16)> _ Structure S3 Dim F1 As Byte Dim F2 As Integer Module alignment Sub Main() Console.WriteLine("Marshal.SizeOf(typeof(S1)) = 0", Marshal.SizeOf(GetType(S1))) Console.WriteLine("Marshal.SizeOf(typeof(S2)) = 0", Marshal.SizeOf(GetType(S2))) Console.WriteLine("Marshal.SizeOf(typeof(S3)) = 0", Marshal.SizeOf(GetType(S3))) Console.WriteLine() Console.ReadLine() End Sub End Module using System.Collections.Generic; using System.Text; namespace alignment // 1 バイトアラインメント [StructLayout(LayoutKind.Sequential, Pack = 1)] struct S1 byte F1; int F2; // 1 バイトアラインメントで 8 バイト分確保する [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8)] struct S2-11-
byte F1; int F2; // 1 バイトアラインメントで 16 バイト分確保する [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 16)] struct S3 byte F1; int F2; class alignment static void Main(string[] args) Console.WriteLine("Marshal.SizeOf(typeof(S1)) = 0", Marshal.SizeOf(typeof(S1))); Console.WriteLine("Marshal.SizeOf(typeof(S2)) = 0", Marshal.SizeOf(typeof(S2))); Console.WriteLine("Marshal.SizeOf(typeof(S3)) = 0", Marshal.SizeOf(typeof(S3))); Console.WriteLine(); unsafe Console.WriteLine("sizeof(typeof(S1)) = 0", sizeof(s1)); Console.WriteLine("sizeof(typeof(S2)) = 0", sizeof(s2)); Console.WriteLine("sizeof(typeof(S3)) = 0", sizeof(s3)); Console.ReadLine(); 実行結果を下記に示す (Visual Basic は上半分丈 ) -12-