StructLayoutAttribute.Pack フィールド

定義

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

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

フィールド値

注釈

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

型インスタンスのフィールドは、次の規則を使用して配置されます。

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

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

  • 配置要件を満たすために、フィールド間にパディングが追加されます。

たとえば、2 つのフィールドと 1 つのByteInt32フィールドで構成される次の構造を、フィールドのさまざまな値と共に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

が 4 に設定されている場合 Pack 、構造体のサイズは既定の場合と同じになります。この場合、型の配置は最大フィールド i3のサイズ (4) で定義されています。

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

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

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 10 進値が 4 つのフィールドで構成されるため、フィールド d5 は 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

が 2 に設定されている場合 Pack 、構造体のサイズは 24 バイトです。 既定のアラインメントと比較して、2 バイトと整数の間の 2 バイトのパディングは削除されました。これは、型のアラインメントが 2 ではなく 4 であるためです。 以降の 3 バイトのパディング a4 は、4 バイトの境界ではなく 2 バイトの境界に配置されるため d5 、1 バイトのパディングに置き換えられました。

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

が 8 に設定されている場合 Pack 、構造体のサイズは既定の場合と同じです。これは、この構造体のすべての配置要件が 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 フィールドは、ディスクおよびネットワーク書き込み操作中に構造体がエクスポートされるときによく使用されます。 このフィールドは、プラットフォーム呼び出しおよび相互運用操作中にも頻繁に使用されます。

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

適用対象