StructLayoutAttribute.Pack Feld

Definition

Steuert die Ausrichtung der Datenfelder einer Klasse oder Struktur im Speicher.

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

Feldwert

Hinweise

Das Pack Feld steuert die Ausrichtung der Felder eines Typs im Arbeitsspeicher. Dies wirkt sich auf aus LayoutKind.Sequential. Standardmäßig ist der Wert 0, was die Standardverpackungsgröße für die aktuelle Plattform angibt. Der Wert von Pack muss 0, 1, 2, 4, 8, 16, 32, 64 oder 128 sein:

Die Felder eines Typs instance werden mithilfe der folgenden Regeln ausgerichtet:

  • Die Ausrichtung des Typs ist die Größe des größten Elements (1, 2, 4, 8 usw., Bytes) oder die angegebene Packgröße, je nachdem, welcher Wert kleiner ist.

  • Jedes Feld muss an Feldern seiner eigenen Größe (1, 2, 4, 8 usw., Bytes) oder der Ausrichtung des Typs ausgerichtet sein, je nachdem, welcher Wert kleiner ist. Da die Standardausrichtung des Typs die Größe des größten Elements ist, das größer oder gleich allen anderen Feldlängen ist, bedeutet dies in der Regel, dass Felder nach ihrer Größe ausgerichtet werden. Selbst wenn das größte Feld in einem Typ eine 64-Bit-Ganzzahl (8 Byte) ist oder das Feld Pack auf 8 festgelegt ist, Byte richten Felder an 1-Byte-Grenzen, Int16 Felder an 2-Byte-Grenzen und Int32 Felder an 4-Byte-Grenzen aus.

  • Die Auffüllung wird zwischen den Feldern hinzugefügt, um die Ausrichtungsanforderungen zu erfüllen.

Betrachten Sie beispielsweise die folgende Struktur, die aus zwei Byte Feldern und einem Int32 Feld besteht, wenn sie mit verschiedenen Werten für das Pack Feld verwendet wird.

using System;

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

Wichtig

Um die C#-Beispiele erfolgreich zu kompilieren, müssen Sie den /unsafe Compilerschalter angeben.

Wenn Sie die Standardverpackungsgröße angeben, beträgt die Größe der Struktur 8 Bytes. Die beiden Bytes belegen die ersten beiden Bytes des Arbeitsspeichers, da Bytes an Ein-Byte-Grenzen ausgerichtet sein müssen. Da die Standardausrichtung des Typs 4 Bytes ist, was die Größe der größten Felder ist, i3gibt es zwei Bytes Auffüllung gefolgt vom Ganzzahlfeld.

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

Wenn Pack auf 2 festgelegt ist, beträgt die Größe der Struktur 6 Bytes. Wie zuvor belegen die beiden Bytes die ersten beiden Bytes des Arbeitsspeichers. Da Felder jetzt an 2-Byte-Grenzen ausgerichtet sind, gibt es keine Auffüllung zwischen dem zweiten Byte und der ganzzahligen Zahl.

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

Wenn Pack auf 4 festgelegt ist, ist die Größe der Struktur identisch mit dem Standardfall, in dem die Ausrichtung des Typs durch die Größe des größten Felds definiert wurde, i3das 4 ist.

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

Wenn Pack auf 8 festgelegt ist, ist die Größe der Struktur immer noch die gleiche wie im Standardfall, da das i3 Feld an einer 4-Byte-Grenze ausgerichtet wird, die kleiner als die im Feld Pack angegebene 8-Byte-Grenze ist.

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

Um ein weiteres Beispiel zu nehmen, betrachten Sie die folgende Struktur, die aus zwei Bytefeldern, einem 32-Bit-Ganzzahlfeld mit Vorzeichen, einem Bytearray mit einem einzelnen Element und einem Dezimalwert besteht. Bei der Standardverpackungsgröße beträgt die Größe der Struktur 28 Bytes. Die beiden Bytes belegen die ersten beiden Bytes des Arbeitsspeichers, gefolgt von zwei Bytes Des Abstands, gefolgt von der ganzen Zahl. Als Nächstes folgt das Ein-Byte-Array, gefolgt von drei Byte des Abstands. Schließlich wird das Decimal Feld d5 an einer 4-Byte-Grenze ausgerichtet, da ein Dezimalwert aus vier Int32 Feldern besteht. Seine Ausrichtung basiert also auf der Größe des größten seiner Felder und nicht auf der Größe der Decimal Struktur als Ganzes.

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

Wenn Pack auf 2 festgelegt ist, beträgt die Größe der Struktur 24 Bytes. Im Vergleich zur Standardausrichtung wurden die zwei Bytes des Abstands zwischen den beiden Bytes und der ganzen Zahl entfernt, da die Ausrichtung des Typs jetzt 4 statt 2 ist. Und die drei Bytes des Abstands nach a4 wurden durch ein Byte des Auffüllens ersetzt, da d5 sie jetzt an einer 2-Byte-Grenze und nicht an einer 4-Byte-Grenze ausgerichtet werden.

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

Wenn Pack auf 8 festgelegt ist, ist die Größe der Struktur die gleiche wie im Standardfall, da alle Ausrichtungsanforderungen in dieser Struktur kleiner als 8 sind.

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

Das Pack Feld wird häufig verwendet, wenn Strukturen während schreibvorgängen von Datenträgern und Netzwerken exportiert werden. Das Feld wird auch häufig bei Plattformaufruf- und Interoperabilitätsvorgängen verwendet.

Gelegentlich wird das Feld verwendet, um den Speicherbedarf zu reduzieren, indem eine engere Packungsgröße erzeugt wird. Diese Nutzung erfordert jedoch eine sorgfältige Berücksichtigung der tatsächlichen Hardwareeinschränkungen und kann tatsächlich die Leistung beeinträchtigen.

Gilt für: