StructLayoutAttribute.Pack Feld

Definition

Steuert die Ausrichtung von Datenfeldern einer Klasse oder Struktur im Arbeitsspeicher.

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. Sie wirkt sich auf die LayoutKind.Sequential Eigenschaft aus. Der Wert gibt die Standardverpackungsgröße für die aktuelle Plattform an. Der Wert von Pack muss 0, 1, 2, 4, 8, 16, 32, 64 oder 128 sein. Der Standardwert ist 0.

Die Felder einer Typinstanz werden mithilfe der folgenden Regeln ausgerichtet:

  • Die Ausrichtung eines Typs ist die Größe des größten Elements (z. B. 1, 2, 4 oder 8 Byte) oder die angegebene Verpackungsgröße, je nachdem, welche Größe kleiner ist.
  • Jedes Feld muss sich an Feldern mit eigener Größe oder der Ausrichtung des Typs ausrichten, 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 von ihrer Größe ausgerichtet werden. Selbst wenn das größte Feld eines Typs eine 64-Bit-Ganzzahl (8 Byte) oder das Pack-Feld auf 8 festgelegt ist, werden Felder an 1-Byte-Begrenzungen ausgerichtet, ByteInt16 Felder an 2-Byte-Begrenzungen ausgerichtet und Int32 Felder an 4-Byte-Begrenzungen ausgerichtet.
  • Abstand wird zwischen 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;
}

Important

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 Byte. Die beiden Bytes belegen die ersten beiden Bytes des Arbeitsspeichers, da Bytes an 1-Byte-Begrenzungen ausgerichtet werden müssen. Da die Standardausrichtung des Typs 4 Byte ist, die die Größe der größten Felder darstellt, i3gibt es zwei Bytes Abstand gefolgt vom ganzzahligen Feld.

using System;
using System.Runtime.InteropServices;

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

public class Example1
{
    public unsafe static void Main()
    {
        ExampleStruct1 ex = new();
        byte* addr = (byte*)&ex;
        Console.WriteLine("Size:      {0}", sizeof(ExampleStruct1));
        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 Byte. Wie zuvor belegen die beiden Bytes die ersten beiden Bytes des Arbeitsspeichers. Da Felder jetzt an 2-Byte-Begrenzungen ausgerichtet sind, gibt es keinen Abstand zwischen dem zweiten Byte und der ganzen Zahl.

using System;
using System.Runtime.InteropServices;

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

public class Example2
{
    public unsafe static void Main()
    {
        ExampleStruct2 ex = new();
        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);
    }
}
// The example displays the following output:
//       Size:      6
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 2

Wenn Pack sie auf 4 festgelegt ist, entspricht die Größe der Struktur dem Standardfall, bei dem die Ausrichtung des Typs durch die Größe des größten Felds definiert wurde, i3was 4 ist.

using System;
using System.Runtime.InteropServices;

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

public class Example3
{
    public unsafe static void Main()
    {
        ExampleStruct3 ex = new();
        byte* addr = (byte*)&ex;
        Console.WriteLine("Size:      {0}", sizeof(ExampleStruct3));
        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 die Größe der Struktur auf 8 festgelegt ist, entspricht die Größe der Struktur weiterhin dem Standardfall, da das i3 Feld an einer Grenze von 4 Byte ausgerichtet ist, die kleiner als die durch das Feld "Pack" angegebene Grenze von 8 Byte ist.

using System;
using System.Runtime.InteropServices;

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

public class Example4
{
    public unsafe static void Main()
    {
        ExampleStruct4 ex = new();
        byte* addr = (byte*)&ex;
        Console.WriteLine("Size:      {0}", sizeof(ExampleStruct4));
        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 betrachten, betrachten Sie die folgende Struktur, die aus zwei Bytefeldern besteht, einem 32-Bit-ganzzahligen Feld mit Vorzeichen, einem Einzelelementbytearray und einem Dezimalwert. Bei der Standardverpackungsgröße beträgt die Größe der Struktur 28 Byte in .NET Framework und 32 Byte in .NET 5+. Die beiden Bytes belegen die ersten beiden Bytes des Arbeitsspeichers, gefolgt von zwei Bytes Abstand, gefolgt von der ganzen Zahl. Als Nächstes befindet sich das 1-Byte-Array, gefolgt von drei Bytes Abstand. Da ein Dezimalwert aus mehreren Feldern besteht, basiert die Ausrichtung auf den größten Feldern und nicht auf der Gesamtgröße der Decimal Struktur. In .NET 5 und neueren Versionen besteht die Decimal-Struktur aus zwei Int32-Feldern und einem 8-Byte-Feld, sodass das feld Decimal, d5, an einer 8-Byte-Grenze ausgerichtet ist. In .NET Framework besteht die Decimal-Struktur aus vier Int32 Feldern, sodass das feld Decimal, d5, an einer 4-Byte-Grenze ausgerichtet ist.

using System;

unsafe struct ExampleStruct5
{

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

public class Example5
{
    public unsafe static void Main()
    {
        ExampleStruct5 ex = new();
        byte* addr = (byte*)&ex;
        Console.WriteLine("Size:      {0}", sizeof(ExampleStruct5));
        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:
//
// .NET 5+:
//       Size:      32
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4
//       a4 Offset: 8
//       d5 Offset: 16
//
// .NET Framework:
//       Size:      28
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4
//       a4 Offset: 8
//       d5 Offset: 12

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

using System;
using System.Runtime.InteropServices;

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

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

public class Example6
{
    public unsafe static void Main()
    {
        ExampleStruct6 ex = new();
        byte* addr = (byte*)&ex;
        Console.WriteLine("Size:      {0}", sizeof(ExampleStruct6));
        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 die Größe der Struktur auf 16 festgelegt ist, entspricht die Größe der Struktur im Standardfall, da alle Ausrichtungsanforderungen in dieser Struktur kleiner als 16 sind.

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 16)]
unsafe struct ExampleStruct7
{

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

public class Example7
{
    public unsafe static void Main()
    {
        ExampleStruct7 ex = new();
        byte* addr = (byte*)&ex;
        Console.WriteLine("Size:      {0}", sizeof(ExampleStruct7));
        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:
//
// .NET 5+:
//       Size:      32
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4
//       a4 Offset: 8
//       d5 Offset: 16
//
// .NET Framework:
//       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 Datenträger- und Netzwerkschreibvorgängen exportiert werden. Das Feld wird auch häufig während plattformübergreifender Aufruf- und Interoperabilitätsvorgänge verwendet.

Gelegentlich wird das Feld verwendet, um die Speicheranforderungen zu reduzieren, indem eine engere Verpackungsgröße erzeugt wird. Diese Verwendung erfordert jedoch eine sorgfältige Prüfung der tatsächlichen Hardwareeinschränkungen und kann tatsächlich die Leistung beeinträchtigen.

Gilt für: