StructLayoutAttribute.Pack Veld

Definitie

Hiermee bepaalt u de uitlijning van gegevensvelden van een klasse of structuur in het geheugen.

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

Waarde van veld

Opmerkingen

Het Pack veld bepaalt de uitlijning van de velden van een type in het geheugen. Dit is van invloed op de LayoutKind.Sequential eigenschap. De waarde geeft de standaardverpakkingsgrootte voor het huidige platform aan. De waarde moet Pack 0, 1, 2, 4, 8, 16, 32, 64 of 128 zijn. De standaardwaarde is 0.

De velden van een typeinstantie worden uitgelijnd met behulp van de volgende regels:

  • De uitlijning van een type is de grootte van het grootste element (bijvoorbeeld 1, 2, 4 of 8 bytes) of de opgegeven verpakkingsgrootte, afhankelijk van wat kleiner is.
  • Elk veld moet worden uitgelijnd met velden van een eigen grootte of de uitlijning van het type, afhankelijk van wat kleiner is. Omdat de standaarduitlijning van het type de grootte is van het grootste element, dat groter is dan of gelijk is aan alle andere veldlengten, betekent dit meestal dat velden worden uitgelijnd op hun grootte. Zelfs als het grootste veld in een type bijvoorbeeld een 64-bits geheel getal (8-bytes) is of als het veld Pack is ingesteld op 8, Byte worden velden uitgelijnd op 1-bytegrenzen, Int16 velden uitgelijnd op 2-bytegrenzen en Int32 velden uitgelijnd op 4-bytegrenzen.
  • Opvulling wordt toegevoegd tussen velden om te voldoen aan de vereisten voor uitlijning.

Denk bijvoorbeeld aan de volgende structuur, die bestaat uit twee Byte velden en één Int32 veld, wanneer deze wordt gebruikt met verschillende waarden voor het Pack veld.

using System;

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

Important

Als u de C#-voorbeelden wilt compileren, moet u de /unsafe compilerswitch opgeven.

Als u de standaardverpakkingsgrootte opgeeft, is de grootte van de structuur 8 bytes. De twee bytes bezetten de eerste twee bytes geheugen, omdat bytes moeten worden uitgelijnd op een-bytegrenzen. Omdat de standaarduitlijning van het type 4 bytes is, wat de grootte is van de grootste velden, i3zijn er twee bytes aan opvulling gevolgd door het veld geheel getal.

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

Als Pack deze is ingesteld op 2, is de grootte van de structuur 6 bytes. Net als voorheen bezetten de twee bytes de eerste twee bytes geheugen. Omdat velden nu zijn uitgelijnd op grenzen van twee bytes, is er geen opvulling tussen de tweede byte en het gehele getal.

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

Als Pack deze is ingesteld op 4, is de grootte van de structuur hetzelfde als in het standaardscenario, waarbij de uitlijning van het type is gedefinieerd door de grootte van het grootste veld, i3wat 4 is.

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

Als Pack deze is ingesteld op 8, is de grootte van de structuur nog steeds gelijk aan in het standaardscenario, omdat het i3 veld is uitgelijnd op een grens van 4 bytes, die kleiner is dan de grens van 8 bytes die is opgegeven door het veld 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

Als u nog een voorbeeld wilt nemen, kunt u de volgende structuur overwegen, die bestaat uit twee bytevelden, één 32-bits geheel getalveld, één bytematrix met één element en een decimale waarde. Met de standaardverpakkingsgrootte is de grootte van de structuur 28 bytes in .NET Framework en 32 bytes in .NET 5+. De twee bytes bezetten de eerste twee bytes geheugen, gevolgd door twee bytes aan opvulling, gevolgd door het gehele getal. Vervolgens is de matrix met één byte, gevolgd door drie bytes aan opvulling. Omdat een decimale waarde uit meerdere velden bestaat, is de uitlijning gebaseerd op het grootste deel van de velden in plaats van de grootte van de Decimal structuur als geheel. In .NET 5 en latere versies bestaat de structuur Decimal uit twee Int32 velden en één veld met 8 bytes, dus het veld Decimal, d5, wordt uitgelijnd op een grens van 8 bytes. In .NET Framework bestaat de structuur Decimal uit vier Int32 velden, zodat het veld Decimal, d5, wordt uitgelijnd op een grens van 4 bytes.

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

Als Pack deze is ingesteld op 2, is de grootte van de structuur 24 bytes. In vergelijking met de standaarduitlijning zijn de twee bytes aan opvulling tussen de twee bytes en het gehele getal verwijderd omdat de uitlijning van het type nu 4 is in plaats van 2. En de drie bytes aan opvulling nadat a4 ze zijn vervangen door één byte van opvulling, worden nu d5 uitgelijnd op een grens van 2 bytes in plaats van een 4-bytegrens.

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

Als Pack deze is ingesteld op 16, is de grootte van de structuur hetzelfde als in het standaardscenario, omdat alle uitlijningsvereisten in deze structuur kleiner zijn dan 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

Het Pack veld wordt vaak gebruikt wanneer structuren worden geëxporteerd tijdens schijf- en netwerkschrijfbewerkingen. Het veld wordt ook vaak gebruikt tijdens het aanroepen van het platform en interop-bewerkingen.

Af en toe wordt het veld gebruikt om geheugenvereisten te verminderen door een strakkere verpakkingsgrootte te produceren. Dit gebruik vereist echter zorgvuldige overweging van werkelijke hardwarebeperkingen en kan de prestaties daadwerkelijk verminderen.

Van toepassing op