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 位元組界限上的欄位對齊。

  • 欄位之間會新增填補,以滿足對齊需求。

例如,假設下列結構是由兩 Byte 個欄位和一個 Int32 欄位所組成,當欄位搭配各種值 Pack 使用時。

using System;

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

重要

若要成功編譯 C# 範例,您必須指定 /unsafe 編譯器參數。

如果您指定預設封裝大小,結構的大小會是 8 個位元組。 兩個位元組佔用前兩個位元組的記憶體,因為位元組必須對齊一位元組界限。 因為類型的預設對齊方式是 4 個位元組,也就是其最大欄位的大小, i3 所以有兩個位元組的填補,後面接著整數位段。

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

如果 Pack 設定為 2,結構的大小會是 6 個位元組。 如同之前,這兩個位元組佔用前兩個位元組的記憶體。 因為欄位現在對齊 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,結構的大小會與預設案例相同,其中類型對齊是由其最大欄位的大小所定義, 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

如果 Pack 設定為 8,結構的大小仍然與預設案例相同,因為 i3 欄位會對齊 4 位元組界限,這小於 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

若要採用另一個範例,請考慮下列結構,其中包含兩個位元組欄位、一個 32 位帶正負號的整數位段、一個單一元素位元組陣列,以及十進位值。 使用預設封裝大小時,結構的大小為 28 個位元組。 這兩個位元組佔用前兩個位元組的記憶體,後面接著兩個位元組填補,後面接著整數。 接下來是一位元組陣列,後面接著三個位元組填補。 最後, Decimal 欄位 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

如果 Pack 設定為 2,結構的大小為 24 個位元組。 相較于預設對齊方式,已移除兩個位元組與整數之間的兩個位元組填補,因為類型的對齊方式現在是 4,而不是 2。 而且之後 a4 的三個位元組填補已由一個位元組填補取代,因為 d5 現在會對齊 2 位元組界限,而不是 4 位元組界限。

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 磁片和網路寫入作業期間匯出結構時,通常會使用 欄位。 欄位在平臺叫用和 Interop 作業期間也經常使用。

偶爾會使用 欄位來減少記憶體需求,方法是產生更緊密的封裝大小。 不過,此使用方式需要仔細考慮實際的硬體條件約束,而且實際上可能會降低效能。

適用於