Share via


StructLayoutAttribute.Pack Campo

Definizione

Controlla l'allineamento dei campi dati di una classe o una struttura nella memoria.

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

Valore del campo

Commenti

Il Pack campo controlla l'allineamento dei campi di un tipo in memoria. Influisce sulla LayoutKind.Sequential proprietà . Il valore indica le dimensioni di compressione predefinite per la piattaforma corrente. Il valore di Pack deve essere 0, 1, 2, 4, 8, 16, 32, 64 o 128. Il valore predefinito è 0.

I campi di un'istanza di tipo vengono allineati usando le regole seguenti:

  • L'allineamento di un tipo è la dimensione dell'elemento più grande , ad esempio 1, 2, 4 o 8 byte, o la dimensione di compressione specificata, a qualsiasi valore inferiore.
  • Ogni campo deve essere allineato con i campi di dimensioni o l'allineamento del tipo, a qualsiasi valore inferiore. Poiché l'allineamento predefinito del tipo è la dimensione dell'elemento più grande, maggiore o uguale a tutte le altre lunghezze di campo, in genere significa che i campi sono allineati in base alle dimensioni. Ad esempio, anche se il campo più grande di un tipo è un numero intero a 64 bit (8 byte) o il campo Pack è impostato su 8, Byte i campi sono allineati su limiti a 1 byte, Int16 i campi sono allineati su limiti a 2 byte e Int32 i campi sono allineati su limiti a 4 byte.
  • La spaziatura interna viene aggiunta tra i campi per soddisfare i requisiti di allineamento.

Si consideri ad esempio la struttura seguente, costituita da due Byte campi e da un Int32 campo, quando viene usata con vari valori per il Pack campo.

using System;

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

Importante

Per compilare correttamente gli esempi C#, è necessario specificare l'opzione del /unsafe compilatore.

Se si specifica la dimensione di compressione predefinita, la dimensione della struttura è di 8 byte. I due byte occupano i primi due byte di memoria, perché i byte devono essere allineati ai limiti di un byte. Poiché l'allineamento predefinito del tipo è di 4 byte, ovvero la dimensione dei campi più grandi, i3, sono presenti due byte di spaziatura interna seguita dal campo integer.

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

Se Pack è impostato su 2, la dimensione della struttura è di 6 byte. Come in precedenza, i due byte occupano i primi due byte di memoria. Poiché i campi ora sono allineati ai limiti a 2 byte, non esiste una spaziatura interna tra il secondo byte e il numero intero.

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

Se Pack è impostato su 4, le dimensioni della struttura sono uguali a nel caso predefinito, in cui l'allineamento del tipo è stato definito dalle dimensioni del relativo campo più grande, i3, ovvero 4.

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

Se Pack è impostato su 8, le dimensioni della struttura sono uguali a quelle del case predefinito, perché il i3 campo si allinea su un limite a 4 byte, minore del limite di 8 byte specificato dal campo Pack.

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

Per un altro esempio, si consideri la struttura seguente, costituita da due campi di byte, un campo intero con segno a 32 bit, una matrice di byte a elemento singolo e un valore decimale. Con le dimensioni predefinite di compressione, le dimensioni della struttura sono pari a 28 byte in .NET Framework e 32 byte in .NET 5+. I due byte occupano i primi due byte di memoria, seguiti da due byte di spaziatura interna, seguiti dal numero intero. Successivamente è la matrice a un byte, seguita da tre byte di spaziatura interna. Poiché un valore decimale è costituito da diversi campi, l'allineamento si basa sul più grande dei relativi campi anziché sulle dimensioni della Decimal struttura nel suo complesso. In .NET 5 e versioni successive la Decimal struttura è costituita da due Int32 campi e da un campo a 8 byte, quindi il Decimal campo, d5, viene allineato su un limite a 8 byte. In .NET Framework la Decimal struttura è costituita da quattro Int32 campi, quindi il Decimal campo d5 viene allineato su un limite a 4 byte.

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

Se Pack è impostato su 2, la dimensione della struttura è di 24 byte. Rispetto all'allineamento predefinito, i due byte di spaziatura interna tra i due byte e l'intero sono stati rimossi perché l'allineamento del tipo è ora 4 anziché 2. E i tre byte di spaziatura interna dopo a4 sono stati sostituiti da un byte di spaziatura interna, dal momento che d5 ora si allinea su un limite a 2 byte anziché su un limite a 4 byte.

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

Se Pack è impostato su 16, le dimensioni della struttura sono uguali a quelle del caso predefinito, perché tutti i requisiti di allineamento in questa struttura sono inferiori a 16.

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

Il Pack campo viene spesso usato quando le strutture vengono esportate durante le operazioni di scrittura su disco e di rete. Il campo viene spesso usato anche durante le operazioni di chiamata e interoperabilità della piattaforma.

In alcuni casi, il campo viene usato per ridurre i requisiti di memoria producendo una dimensione di compressione più stretta. Tuttavia, questo utilizzo richiede un'attenta considerazione dei vincoli hardware effettivi e può effettivamente compromettere le prestazioni.

Si applica a