StructLayoutAttribute.Pack フィールド

定義

メモリ内のクラスまたは構造体のデータ フィールドのアライメントを制御します。

public: int Pack;
public int Pack;
val mutable Pack : int
Public Pack As Integer 

フィールド値

Int32

注釈

フィールドは、 Pack メモリ内の型のフィールドの配置を制御します。 に影響 LayoutKind.Sequential します。 既定では、値は0です。これは、現在のプラットフォームの既定のパッキングサイズを示します。 の値は、 Pack 0、1、2、4、8、16、32、64、128のいずれかである必要があります。

型インスタンスのフィールドは、次の規則に従ってアラインされます。

  • 型のアラインメントは、最大の要素 (1、2、4、8など) のサイズ、または指定されたパッキングサイズのいずれか小さい方になります。

  • 各フィールドは、独自のサイズ (1、2、4、8など) のフィールド、または型のアラインメントのいずれか小さい方に揃える必要があります。 型の既定のアラインメントは、それ以外のすべてのフィールド長と同じかそれ以上の要素のサイズであるため、通常はフィールドがそのサイズに合わせて配置されます。 たとえば、型の最大のフィールドが64ビット (8 バイト) の整数である場合、またはパックのフィールドが8に設定されている場合でも、1バイトの境界にフィールドが配置され、フィールドが2バイトの境界に配置され、 Byte Int16 フィールドが Int32 4 バイトの境界に沿って配置されます。

  • 配置要件を満たすために、フィールドの間に埋め込みが追加されます。

たとえば、2つのフィールド Byte と1つのフィールドで構成される、 Int32 フィールドのさまざまな値と共に使用される次の構造を考えてみ Pack ます。

using System;

struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

重要

C# の例を正常にコンパイルするには、コンパイラスイッチを指定する必要があり /unsafe ます。

既定のパッキングサイズを指定した場合、構造体のサイズは8バイトになります。 バイトは1バイトの境界に合わせて配置する必要があるため、2バイトは最初の2バイトのメモリを占有します。 型の既定の配置は、最大のフィールドのサイズである4バイトであるため i3 、2バイトのパディングの後に整数フィールドが続きます。

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=0)]
struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct ex = new ExampleStruct();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct));
      Console.WriteLine("b1 Offset: {0}", &ex.b1 - addr);
      Console.WriteLine("b2 Offset: {0}", &ex.b2 - addr);
      Console.WriteLine("i3 Offset: {0}", (byte*) &ex.i3 - addr);
   }
}
// The example displays the following output:
//       Size:      8
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4

が2に設定されている場合、 Pack 構造体のサイズは6バイトになります。 前と同様に、2バイトは最初の2バイトのメモリを占有します。 フィールドが2バイトの境界に配置されるようになったため、2番目のバイトと整数の間には余白がありません。

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=2)]
struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct ex = new ExampleStruct();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct));
      Console.WriteLine("b1 Offset: {0}", &ex.b1 - addr);
      Console.WriteLine("b2 Offset: {0}", &ex.b2 - addr);
      Console.WriteLine("i3 Offset: {0}", (byte*) &ex.i3 - addr);
   }
}
// The example displays the following output:
//       Size:      6
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 2

Packが4に設定されている場合、構造体のサイズは、既定のケースと同じです。この場合、型のアラインメントは、最大の4のフィールドのサイズによって定義されてい i3 ます。

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=4)]
struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct ex = new ExampleStruct();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct));
      Console.WriteLine("b1 Offset: {0}", &ex.b1 - addr);
      Console.WriteLine("b2 Offset: {0}", &ex.b2 - addr);
      Console.WriteLine("i3 Offset: {0}", (byte*) &ex.i3 - addr);
   }
}
// The example displays the following output:
//       Size:      8
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4

Packが8に設定されている場合、構造体のサイズは、既定の場合と同じです。これは、フィールドが、 i3 パックフィールドで指定される8バイト境界よりも小さい4バイトの境界上に配置されるためです。

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=8)]
struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct ex = new ExampleStruct();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct));
      Console.WriteLine("b1 Offset: {0}", &ex.b1 - addr);
      Console.WriteLine("b2 Offset: {0}", &ex.b2 - addr);
      Console.WriteLine("i3 Offset: {0}", (byte*) &ex.i3 - addr);
   }
}
// The example displays the following output:
//       Size:      8
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4

別の例を使用するには、次の構造を考えてみます。これは、2つのバイトフィールド、1 32 ビット符号付き整数フィールド、1つの単一要素のバイト配列、および10進数の値で構成されています。 既定のパッキングサイズでは、構造体のサイズは28バイトになります。 2バイトは、最初の2バイトのメモリを占有し、次に2バイトのパディングを続け、その後に整数を配置します。 次は1バイト配列で、その後に3バイトの余白が続きます。 最後に、このフィールドは、 Decimal 4 バイトの境界に配置されます。これは、10進値が4つのフィールドで構成されるためです Int32 。そのため、配置は、構造体全体のサイズではなく、フィールドの最大サイズに基づいてい Decimal ます。

using System;
using System.Runtime.InteropServices;

unsafe struct ExampleStruct2
{

   public byte b1;
   public byte b2;
   public int i3;
   public fixed byte a4[1];
   public decimal d5;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct2 ex = new ExampleStruct2();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct2));
      Console.WriteLine("b1 Offset: {0}", &ex.b1 - addr);
      Console.WriteLine("b2 Offset: {0}", &ex.b2 - addr);
      Console.WriteLine("i3 Offset: {0}", (byte*) &ex.i3 - addr);
      Console.WriteLine("a4 Offset: {0}", ex.a4 - addr);
      Console.WriteLine("d5 Offset: {0}", (byte*) &ex.d5 - addr);
   }
}
// The example displays the following output:
//       Size:      28
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4
//       a4 Offset: 8
//       d5 Offset: 12

Packが2に設定されている場合、構造体のサイズは24バイトになります。 既定の配置と比較すると、2バイトと整数の間の2バイトの埋め込みが削除されました。これは、型のアラインメントが2ではなく4になったためです。 との後の3バイトの埋め込みは、 a4d5 4 バイト境界ではなく2バイト境界に配置されるようになりました。

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 2)]
unsafe struct ExampleStruct2
{

   public byte b1;
   public byte b2;
   public int i3;
   public fixed byte a4[1];
   public decimal d5;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct2 ex = new ExampleStruct2();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct2));
      Console.WriteLine("b1 Offset: {0}", &ex.b1 - addr);
      Console.WriteLine("b2 Offset: {0}", &ex.b2 - addr);
      Console.WriteLine("i3 Offset: {0}", (byte*) &ex.i3 - addr);
      Console.WriteLine("a4 Offset: {0}", ex.a4 - addr);
      Console.WriteLine("d5 Offset: {0}", (byte*) &ex.d5 - addr);
   }
}
// The example displays the following output:
//       Size:      24
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 2
//       a4 Offset: 6
//       d5 Offset: 8

Packが8に設定されている場合、この構造体のすべてのアラインメント要件が8未満であるため、構造体のサイズは既定の場合と同じになります。

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 8)]
unsafe struct ExampleStruct2
{

   public byte b1;
   public byte b2;
   public int i3;
   public fixed byte a4[1];
   public decimal d5;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct2 ex = new ExampleStruct2();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct2));
      Console.WriteLine("b1 Offset: {0}", &ex.b1 - addr);
      Console.WriteLine("b2 Offset: {0}", &ex.b2 - addr);
      Console.WriteLine("i3 Offset: {0}", (byte*) &ex.i3 - addr);
      Console.WriteLine("a4 Offset: {0}", ex.a4 - addr);
      Console.WriteLine("d5 Offset: {0}", (byte*) &ex.d5 - addr);
   }
}
// The example displays the following output:
//       Size:      28
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4
//       a4 Offset: 8
//       d5 Offset: 12

この Pack フィールドは、ディスクおよびネットワークの書き込み操作中に構造がエクスポートされるときに頻繁に使用されます。 また、このフィールドは、プラットフォーム呼び出しと相互運用操作中に頻繁に使用されます。

場合によっては、より厳密なパッキングサイズを生成することによって、メモリ要件を減らすためにフィールドが使用されることがあります。 ただし、この使用には実際のハードウェアの制約を慎重に検討する必要があり、実際にはパフォーマンスが低下する可能性があります。

適用対象