Condividi tramite


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 predefinite di imballaggio 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 sono 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 imballaggio specificata, che tuttavia è più piccola.
  • Ogni campo deve essere allineato ai campi di dimensioni personalizzate o all'allineamento del tipo, che tuttavia è più piccolo. Poiché l'allineamento predefinito del tipo è la dimensione dell'elemento più grande, maggiore o uguale a tutte le altre lunghezze del campo, questo significa in genere che i campi sono allineati alle relative dimensioni. Ad esempio, anche se il campo più grande in un tipo è un intero a 64 bit (8 byte) o il campo Pack è impostato su 8, i campi si allineano su limiti a 1 byte, ByteInt16 i campi si allineano su limiti a 2 byte e Int32 i campi si allineano 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 un Int32 campo, quando viene usato 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 specificano le dimensioni predefinite della confezione, 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 è 4 byte, ovvero la dimensione dei campi più grandi, i3sono 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, le dimensioni della struttura sono 6 byte. Come prima, i due byte occupano i primi due byte di memoria. Poiché i campi sono ora allineati ai limiti di 2 byte, non esiste alcuna spaziatura interna tra il secondo byte e l'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, la dimensione della struttura è uguale al caso predefinito, in cui l'allineamento del tipo è stato definito dalle dimensioni del campo più grande, i3, che è 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, la dimensione della struttura è uguale al caso 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 prendere un altro esempio, prendere in considerazione la struttura seguente, costituita da due campi di byte, un campo intero con segno a 32 bit, una matrice di byte a un singolo elemento e un valore decimale. Con le dimensioni predefinite dell'imballaggio, la dimensione della struttura è di 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 dall'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 campi e da un Int32 campo a 8 byte, quindi il Decimal campo, d5, si allinea su un limite di 8 byte. In .NET Framework la Decimal struttura è costituita da quattro Int32 campi, quindi il Decimal campo, d5, si allinea su un limite di 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, le dimensioni della struttura sono 24 byte. Rispetto all'allineamento predefinito, i due byte di spaziatura 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 essere stati sostituiti da un byte di riempimento, poiché d5 ora si allinea su un limite a 2 byte anziché su un limite di 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 al 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 operazioni di scrittura su disco e di rete. Il campo viene usato spesso anche durante le operazioni di richiamo e interoperabilità della piattaforma.

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

Si applica a