2014-10-24T22:35:07の更新内容

programming/netfx/struct/2_sizeof/index.wiki.txt

current previous
1,424 0,0
+
${smdncms:title,構造体のサイズ}
+
${smdncms:header_title,構造体のサイズ (Marshal.SizeOf, sizeof)}
+
${smdncms:keywords,サイズ,Marshal.SizeOf,sizeof}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
//#navi(..)
+

          
+
-関連するページ
+
--[[programming/netfx/basic_types/0_characteristics]]
+
--[[programming/netfx/structlayout_fieldoffset]]
+
--[[programming/netfx/tips/convert_struct_and_bytearray]]
+
--[[programming/netfx/arrays/3_structfields]]
+

          
+
#adunit
+

          
+
*Marshal.SizeOfメソッド [#Marshal.SizeOf]
+
整数型など型のサイズが定義されている構造体の場合、&msdn(netfx,member,System.Runtime.InteropServices.Marshal.SizeOf){Marshal.SizeOfメソッド};を使うことにより型のサイズ(バイト数)を取得することができます。 引数に値やオブジェクトを直接指定するか、``typeof``/``GetType``で取得した型情報を渡すことにより、その型のサイズを取得することが出来ます。
+

          
+
#tabpage(codelang=cs)
+
#code{{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    Console.WriteLine("SizeOf({0}) = {1}", 16, Marshal.SizeOf(16)); // int
+
    Console.WriteLine("SizeOf({0}) = {1}", 3L, Marshal.SizeOf(3L)); // long
+
    Console.WriteLine("SizeOf({0}) = {1}", 1.414f, Marshal.SizeOf(1.414f)); // float
+
    Console.WriteLine("SizeOf({0}) = {1}", 3.14, Marshal.SizeOf(3.14)); // double
+
    Console.WriteLine();
+

          
+
    Console.WriteLine("SizeOf({0}) = {1}", typeof(int), Marshal.SizeOf(typeof(int)));
+
    Console.WriteLine("SizeOf({0}) = {1}", typeof(long), Marshal.SizeOf(typeof(long)));
+
    Console.WriteLine("SizeOf({0}) = {1}", typeof(float), Marshal.SizeOf(typeof(float)));
+
    Console.WriteLine("SizeOf({0}) = {1}", typeof(double), Marshal.SizeOf(typeof(double)));
+
    Console.WriteLine("SizeOf({0}) = {1}", typeof(IntPtr), Marshal.SizeOf(typeof(IntPtr)));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Runtime.InteropServices
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Console.WriteLine("SizeOf({0}) = {1}", 16, Marshal.SizeOf(16)) ' Integer
+
    Console.WriteLine("SizeOf({0}) = {1}", 3L, Marshal.SizeOf(3L)) ' Long
+
    Console.WriteLine("SizeOf({0}) = {1}", 1.414F, Marshal.SizeOf(1.414F)) ' Single
+
    Console.WriteLine("SizeOf({0}) = {1}", 3.14, Marshal.SizeOf(3.14)) ' Double
+
    Console.WriteLine()
+

          
+
    Console.WriteLine("SizeOf({0}) = {1}", GetType(Integer), Marshal.SizeOf(GetType(Integer)))
+
    Console.WriteLine("SizeOf({0}) = {1}", GetType(Long), Marshal.SizeOf(GetType(Long)))
+
    Console.WriteLine("SizeOf({0}) = {1}", GetType(Single), Marshal.SizeOf(GetType(Single)))
+
    Console.WriteLine("SizeOf({0}) = {1}", GetType(Double), Marshal.SizeOf(GetType(Double)))
+
    Console.WriteLine("SizeOf({0}) = {1}", GetType(IntPtr), Marshal.SizeOf(GetType(IntPtr)))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
SizeOf(16) = 4
+
SizeOf(3) = 8
+
SizeOf(1.414) = 4
+
SizeOf(3.14) = 8
+

          
+
SizeOf(System.Int32) = 4
+
SizeOf(System.Int64) = 8
+
SizeOf(System.Single) = 4
+
SizeOf(System.Double) = 8
+
SizeOf(System.IntPtr) = 4
+
}}
+

          
+
``IntPtr``は実行環境によってサイズが変わります。 32ビット環境では``4``、64ビット環境では``8``が返されます。 上記の実行結果は32ビット環境でのものです。 ``IntrPtr``のサイズは&msdn(netfx,member,System.IntPtr.Size){IntPtr.Size};プロパティによっても取得することができます。 (関連:[[programming/netfx/environment/0_platform#SystemAndPlatform_32Bit64Bit]])
+

          
+
どのような型でもMarshal.SizeOfでサイズを取得出来るわけではありません。 例えば``DateTime``などアンマネージコードに渡す際のマーシャリング方法が定義されていない型の場合はサイズを取得できません。 型のサイズが取得できない場合、Marshal.SizeOfメソッドは&msdn(netfx,type,System.ArgumentException){ArgumentException};をスローします。
+

          
+
#tabpage(codelang=cs)
+
#code{{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // DateTime型のサイズは取得できない
+
    Console.WriteLine("SizeOf({0}) = {1}", typeof(DateTime), Marshal.SizeOf(typeof(DateTime)));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Runtime.InteropServices
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' DateTime型のサイズは取得できない
+
    Console.WriteLine("SizeOf({0}) = {1}", GetType(DateTime), Marshal.SizeOf(GetType(DateTime)))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
ハンドルされていない例外: System.ArgumentException: 型 'System.DateTime' はアンマネージ構造体としてマーシャリングできません。有効なサイズ、またはオフセットの計算ができません。
+
   場所 System.Runtime.InteropServices.Marshal.SizeOfHelper(Type t, Boolean throwIfNotMarshalable)
+
   場所 System.Runtime.InteropServices.Marshal.SizeOf(Type t)
+
   場所 Sample.Main()
+
}}
+

          
+
``DateTime``のほか、``DateTimeOffset``、``string``や``object``などの参照型のもサイズが取得できません。
+

          
+
構造体の場合では、&msdn(netfx,type,System.Runtime.InteropServices.StructLayoutAttribute){StructLayout属性};で``LayoutKind.Sequential``または``LayoutKind.Explicit``が指定されていればMarshal.SizeOfメソッドで構造体のサイズを取得することができます。
+

          
+
#tabpage(codelang=cs)
+
#code{{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
[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()
+
  {
+
    Console.WriteLine("SizeOf({0}) = {1}", typeof(Point), Marshal.SizeOf(typeof(Point)));
+
    Console.WriteLine("SizeOf({0}) = {1}", typeof(ARGB), Marshal.SizeOf(typeof(ARGB)));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Runtime.InteropServices
+

          
+
<StructLayout(LayoutKind.Sequential)> _
+
Structure Point
+
  Dim X As Integer
+
  Dim Y As Integer
+
End Structure
+

          
+
<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
+
End Structure
+

          
+

          
+
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
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
SizeOf(Point) = 8
+
SizeOf(ARGB) = 4
+
}}
+

          
+
StructLayout属性について詳しくは[[programming/netfx/structlayout_fieldoffset]]を参照してください。
+

          
+
また、.NET Framework 4.5.1以降ではMarshal.SizeOf<T>メソッドが用意されています。 ``typeof``/``GetType``で型情報を指定する代わりに型パラメータ``T``を指定するだけで型のサイズが取得できるようになります。
+

          
+
#tabpage(codelang=cs)
+
#code{{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
[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>());
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果){{
+
SizeOf<int> = 4
+
SizeOf<Point> = 8
+
}}
+

          
+
#tabpage(codelang=vb)
+

          
+
#code{{
+
Imports System
+
Imports System.Runtime.InteropServices
+

          
+
<StructLayout(LayoutKind.Sequential)> _
+
Structure Point
+
  Dim X As Integer
+
  Dim Y As Integer
+
End Structure
+

          
+
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
+
}}
+

          
+
#prompt(実行結果){{
+
SizeOf(Of Integer) = 4
+
SizeOf(Of Point) = 8
+
}}
+
#tabpage-end
+

          
+

          
+
*sizeof [#sizeof]
+
C#では&msdn(netfx,id,eahchzkf){sizeof};によっても型のサイズを取得することができます。 ``sizeof``は``int``や``bool``などの組み込み型に対して使用することができ、定義済みのサイズを返します。 また、''参照型のメンバを含まない''構造体に対して使用することもできますが、その場合は``unsafe``コンテキスト内で使用する必要があります。
+

          
+
#code(cs){{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
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));
+
    }
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果){{
+
sizeof(int) = 4
+
sizeof(long) = 8
+
sizeof(Point) = 8
+
}}
+

          
+
**Marshal.SizeOfとsizeofの違い [#difference_between_Marshal.SizeOf_and_sizeof]
+
型によっては``Marshal.SizeOf``と``sizeof``で異なる結果となる場合があります。 例えばbool型では次のように異なる結果を返します。
+

          
+
#code(cs,Marshal.SizeOfとsizeof){{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    Console.WriteLine("Marshal.SizeOf(typeof(bool)) = {0}", Marshal.SizeOf(typeof(bool)));
+
    Console.WriteLine("sizeof(bool) = {0}", sizeof(bool));
+
  }
+
}
+
}}
+

          
+
#prompt{{
+
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``を返します。
+

          
+
-マーシャリングに関するドキュメント
+
--&msdn(netfx,id,fzhhdwae){プラットフォーム呼び出しによるデータのマーシャリング};
+
---&msdn(netfx,id,ac7ay120){プラットフォーム呼び出しのデータ型};
+
--[[Windows Data Types:http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx]]
+

          
+

          
+
*アラインメント(Pack)・サイズ(Size)
+
``Marshal.SizeOf``および``sizeof``は構造体のアラインメントに応じた結果を返します。 次の例では``StructLayout属性``の``Pack``パラメータを指定して構造体のアラインメントを変更しています。
+

          
+
#code(cs,Marshal.SizeOfとsizeof){{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
// デフォルトのアラインメント (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 {
+
  byte F1; // 1バイト目に配置される
+
  int  F2; // 5〜8バイト目に配置される
+
}
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    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));
+
    }
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果){{
+
Marshal.SizeOf(typeof(S1)) = 8
+
Marshal.SizeOf(typeof(S2)) = 5
+
Marshal.SizeOf(typeof(S3)) = 6
+
Marshal.SizeOf(typeof(S4)) = 8
+

          
+
sizeof(typeof(S1)) = 8
+
sizeof(typeof(S2)) = 5
+
sizeof(typeof(S3)) = 6
+
sizeof(typeof(S4)) = 8
+
}}
+

          
+
同様に``Size``パラメータを指定して構造体のサイズを指定した場合もそれに応じた結果となります。
+

          
+
#code(cs){{
+
using System;
+
using System.Runtime.InteropServices;
+

          
+
// 1バイトアラインメント
+
[StructLayout(LayoutKind.Sequential, Pack = 1)]
+
struct S1 {
+
  byte F1;
+
  int  F2;
+
}
+

          
+
// 1バイトアラインメントで8バイト分確保する
+
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8)]
+
struct S2 {
+
  byte F1;
+
  int  F2;
+
}
+

          
+
// 1バイトアラインメントで16バイト分確保する
+
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 16)]
+
struct S3 {
+
  byte F1;
+
  int  F2;
+
}
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    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));
+
    }
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果){{
+
Marshal.SizeOf(typeof(S1)) = 5
+
Marshal.SizeOf(typeof(S2)) = 8
+
Marshal.SizeOf(typeof(S3)) = 16
+

          
+
sizeof(typeof(S1)) = 5
+
sizeof(typeof(S2)) = 8
+
sizeof(typeof(S3)) = 16
+
}}
+

          
+

          
+

          
+
//#navi(..)
+

          

programming/netfx/struct/index.wiki.txt

current previous
1,9 0,0
+
${smdncms:title,構造体}
+
${smdncms:keywords,構造体,struct}
+

          
+
ここでは.NET Frameworkにおける構造体について解説します。
+

          
+
#adunit
+

          
+
#dir_toc
+