Sdílet prostřednictvím


StructLayoutAttribute.Pack Pole

Definice

Řídí zarovnání datových polí třídy nebo struktury v paměti.

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

Hodnota pole

Poznámky

Pole Pack řídí zarovnání polí typu v paměti. Ovlivňuje vlastnost LayoutKind.Sequential . Hodnota označuje výchozí velikost balení pro aktuální platformu. Hodnota Pack musí být 0, 1, 2, 4, 8, 16, 32, 64 nebo 128. Výchozí hodnota je 0.

Pole instance typu jsou zarovnaná pomocí následujících pravidel:

  • Zarovnání typu je velikost jeho největšího prvku (například 1, 2, 4 nebo 8 bajtů) nebo zadané velikosti balení podle toho, která velikost je menší.
  • Každé pole musí být zarovnané s poli vlastní velikosti nebo s zarovnáním typu podle toho, které z nich je menší. Vzhledem k tomu, že výchozím zarovnáním typu je velikost jeho největšího prvku, která je větší nebo rovna všem ostatním délkám polí, obvykle to znamená, že pole jsou zarovnaná podle velikosti. Například i když je největší pole typu 64bitové (8 bajtové) celé číslo nebo pole Pack je nastavené na 8, Byte pole se zarovnají na 1 bajtové hranice, Int16 pole se zarovnají na 2 bajtové hranice a Int32 pole se zarovnají na 4 bajtové hranice.
  • Mezi pole se přidává odsazení, aby se splnily požadavky na zarovnání.

Zvažte například následující strukturu, která se skládá ze dvou Byte polí a jednoho Int32 pole, pokud se používá s různými hodnotami pole Pack .

using System;

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

Důležité

Pokud chcete úspěšně zkompilovat příklady jazyka C#, musíte zadat přepínač kompilátoru /unsafe .

Pokud zadáte výchozí velikost balení, velikost struktury je 8 bajtů. Tyto dva bajty zabírají první dva bajty paměti, protože bajty musí být zarovnány na jedno bajtových hranicích. Vzhledem k tomu, že výchozí zarovnání typu je 4 bajty, což je velikost jeho největších polí , i3existují dva bajty odsazení následované celočíselným polem.

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

Pokud Pack je nastavená hodnota 2, velikost struktury je 6 bajtů. Stejně jako předtím zabírají dva bajty první dva bajty paměti. Vzhledem k tomu, že pole se teď zarovnají na 2 bajtové hranice, neexistuje mezi druhým bajtem a celočíselným číslem žádné odsazení.

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

Pokud Pack je nastavená hodnota 4, je velikost struktury stejná jako ve výchozím případě, kdy bylo zarovnání typu definováno velikostí jeho největšího pole , i3což je 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

Pokud Pack je nastavena hodnota 8, velikost struktury je stále stejná jako ve výchozím případě, protože i3 pole je zarovnané na hranici 4 bajtů, která je menší než 8 bajtová hranice určená polem Balíček.

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

Chcete-li použít jiný příklad, podívejte se na následující strukturu, která se skládá ze dvou bajtů polí, jednoho 32bitového celočíselného pole se dvěma čísly se dvěma bajtů, jednoho pole se sadou bajtů s jedním prvkem a desítkové hodnoty. Při výchozí velikosti balení je velikost struktury 28 bajtů v rozhraní .NET Framework a 32 bajtů v rozhraní .NET 5+ . Dva bajty zabírají první dva bajty paměti, následované dvěma bajty odsazení a po nich celé číslo. Následuje jedno bajtové pole následované třemi bajty odsazení. Vzhledem k tomu, že desetinná hodnota se skládá z několika polí, zarovnání je založeno na největších polích, nikoli na velikosti Decimal struktury jako celku. V .NET 5 a novějších verzích Decimal se struktura skládá ze dvou Int32 polí a jednoho 8 bajtového pole, takže Decimal pole d5 se zarovná na hranici 8 bajtů. V rozhraní .NET Framework se Decimal struktura skládá ze čtyř Int32 polí, takže Decimal pole d5 se zarovná na hranici 4 bajtů.

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

Pokud Pack je nastavená hodnota 2, velikost struktury je 24 bajtů. Ve srovnání s výchozím zarovnáním byly odebrány dva bajty odsazení mezi dvěma bajty a celým číslem, protože zarovnání typu je nyní 4 místo 2. A tři bajty odsazení za a4 byly nahrazeny jedním bajtem odsazení, protože d5 nyní se zarovná na hranici 2 bajtů, nikoli na hranici 4 bajtů.

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

Pokud Pack je nastavená hodnota 16, velikost struktury je stejná jako ve výchozím případě, protože všechny požadavky na zarovnání v této struktuře jsou menší než 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

Toto Pack pole se často používá při exportu struktur během operací zápisu na disk a do sítě. Pole se také často používá při volání platformy a operacích spolupráce.

Občas se pole používá ke snížení požadavků na paměť tím, že se vytvoří užší velikost balení. Toto použití však vyžaduje pečlivé zvážení skutečných hardwarových omezení a může ve skutečnosti snížit výkon.

Platí pro