StructLayoutAttribute.Pack Mező

Definíció

Egy osztály vagy struktúra adatmezőinek igazítását szabályozza a memóriában.

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

Mező értéke

Megjegyzések

A Pack mező szabályozza egy típus mezőinek igazítását a memóriában. Ez hatással van a tulajdonságra LayoutKind.Sequential . Az érték az aktuális platform alapértelmezett csomagolási méretét jelzi. Az értéknek Pack 0, 1, 2, 4, 8, 16, 32, 64 vagy 128 értékűnek kell lennie. Az alapértelmezett érték 0.

A típuspéldány mezői a következő szabályok szerint vannak igazítva:

  • Egy típus igazítása a legnagyobb elemének (például 1, 2, 4 vagy 8 bájt) vagy a megadott csomagolási méretnek a mérete, amelyik kisebb.
  • Minden mezőnek igazodnia kell a saját méretű mezőkhöz vagy a típus igazításához, attól függően, hogy melyik kisebb. Mivel a típus alapértelmezett igazítása a legnagyobb elem mérete, amely nagyobb vagy egyenlő az összes többi mezőhossznál, ez általában azt jelenti, hogy a mezők mérete igazodik a méretükhöz. Ha például egy típus legnagyobb mezője egy 64 bites (8 bájtos) egész szám, vagy a Csomag mező értéke 8, Byte a mezők 1 bájtos határokhoz igazodnak, Int16 a mezők 2 bájtos határokhoz igazodnak, a mezők pedig Int32 4 bájtos határokhoz igazodnak.
  • A mezők közötti kitöltés az igazítási követelményeknek megfelelően történik.

Vegyük például a következő struktúrát, amely két Byte mezőből és egy Int32 mezőből áll, amikor a mező különböző értékeivel Pack használják.

using System;

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

Important

A C# példák sikeres fordításához meg kell adnia a fordítókapcsolót /unsafe .

Ha megadja az alapértelmezett csomagolási méretet, a szerkezet mérete 8 bájt. A két bájt a memória első két bájtját foglalja el, mivel a bájtok egybájtos határokhoz kell igazodniuk. Mivel a típus alapértelmezett igazítása 4 bájt, amely a legnagyobb mezőinek mérete, i3két bájtnyi kitöltést és egy egész számot tartalmazó mező van.

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

Ha Pack 2 értékre van állítva, a struktúra mérete 6 bájt. A korábbiakhoz hasonlóan a két bájt foglalja el az első két bájt memóriát. Mivel a mezők most már két bájtos határokhoz igazodnak, nincs párnázás a második bájt és az egész szám között.

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

Ha Pack 4-es értékre van állítva, a szerkezet mérete megegyezik az alapértelmezett esettel, ahol a típus igazítását a legnagyobb mező mérete határozza meg, i3ami 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

Ha Pack 8-ra van állítva, a struktúra mérete továbbra is megegyezik az alapértelmezett esettel, mivel a i3 mező egy 4 bájtos határhoz igazodik, amely kisebb, mint a Pack mező által megadott 8 bájtos határ.

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

Egy másik példához vegyük a következő struktúrát, amely két bájtmezőből, egy 32 bites aláírt egész számmezőből, egy egyelemes bájttömbből és egy decimális értékből áll. Az alapértelmezett csomagolási méret esetén a szerkezet mérete 28 bájt .NET Keretrendszerben és 32 bájt .NET 5 bájtban. A két bájt az első két bájt memóriát foglalja el, amelyet két bájtnyi kitöltés követ, majd az egész szám. A következő az egybájtos tömb, amelyet három bájtnyi kitöltés követ. Mivel a decimális érték több mezőből áll, az igazítás a legnagyobb mezőn alapul a Decimal struktúra egészének mérete helyett. Az .NET 5-ös és újabb verzióiban a Decimal struktúra két Int32 mezőből és egy 8 bájtos mezőből áll, így a Decimal mező (d5) egy 8 bájtos határhoz igazodik. A .NET Keretrendszerben a Decimal struktúra négy Int32 mezőből áll, így a Decimal mező(d5) egy 4 bájtos határhoz igazodik.

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

Ha Pack 2 értékre van állítva, a struktúra mérete 24 bájt. Az alapértelmezett igazítással összehasonlítva a két bájt és az egész szám közötti párnázás két bájtja el lett távolítva, mert a típus igazítása most 4 és nem 2. És a három bájtnyi kitöltést egy a4 bájtnyi párnázás váltotta fel, azóta d5 a 4 bájtos határ helyett egy kétbájtos határhoz igazodik.

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

Ha Pack 16-ra van állítva, a szerkezet mérete megegyezik az alapértelmezett esettel, mivel a szerkezet összes igazítási követelménye kisebb, mint 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

A Pack mezőt gyakran használják a lemez- és hálózati írási műveletek során exportált struktúrák esetén. A mezőt gyakran használják a platformhívások és az interop műveletek során is.

A mezőt esetenként a memóriaigény csökkentésére használják szűkebb csomagolási méret előállításával. Ez a használat azonban a tényleges hardverkorlátok gondos mérlegelését igényli, és ténylegesen csökkentheti a teljesítményt.

A következőre érvényes: