StructLayoutAttribute.Pack Fält
Definition
Viktigt
En del information gäller för förhandsversionen av en produkt och kan komma att ändras avsevärt innan produkten blir allmänt tillgänglig. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, avseende informationen som visas här.
Styr justeringen av datafält i en klass eller struktur i minnet.
public: int Pack;
public int Pack;
val mutable Pack : int
Public Pack As Integer
Fältvärde
Kommentarer
Fältet Pack styr justeringen av en typs fält i minnet. Det påverkar egenskapen LayoutKind.Sequential . Värdet anger standardstorleken för paketering för den aktuella plattformen. Värdet Pack för måste vara 0, 1, 2, 4, 8, 16, 32, 64 eller 128. Standardvärdet är 0.
Fälten i en typinstans justeras med hjälp av följande regler:
- Justeringen av en typ är storleken på dess största element (till exempel 1, 2, 4 eller 8 byte) eller den angivna förpackningsstorleken, beroende på vilket som är mindre.
- Varje fält måste justeras efter fält av egen storlek eller justering av typen, beroende på vilket som är mindre. Eftersom standardjusteringen av typen är storleken på dess största element, vilket är större än eller lika med alla andra fältlängder, innebär det vanligtvis att fälten justeras efter deras storlek. Även om det största fältet i en typ till exempel är ett heltal på 64 bitar (8 byte) eller om fältet Pack är inställt på 8, Byte justeras fälten på 1 bytes gränser, Int16 fälten justeras efter 2 bytes gränser och Int32 fälten justeras efter 4 bytes gränser.
- Utfyllnad läggs till mellan fält för att uppfylla justeringskraven.
Tänk till exempel på följande struktur, som består av två Byte fält och ett Int32 fält, när den används med olika värden för fältet Pack .
using System;
struct ExampleStruct
{
public byte b1;
public byte b2;
public int i3;
}
Important
Om du vill kompilera C#-exemplen /unsafe måste du ange kompilatorväxeln.
Om du anger standardstorleken för förpackning är strukturens storlek 8 byte. De två byteen upptar de två första byteen minne eftersom byte måste justeras på en bytes gränser. Eftersom standardjusteringen av typen är 4 byte, vilket är storleken på dess största fält, i3finns det två byte utfyllnad följt av heltalsfältet.
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
Om Pack är inställt på 2 är strukturens storlek 6 byte. Precis som tidigare upptar de två byteen de två första byteen minne. Eftersom fälten nu justeras på 2 bytes gränser, finns det ingen utfyllnad mellan den andra byte och heltal.
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
Om Pack är inställt på 4 är strukturens storlek densamma som i standardfallet, där typens justering definierades av storleken på dess största fält, i3, som är 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
Om Pack är inställt på 8 är strukturens storlek fortfarande densamma som i standardfallet, eftersom i3 fältet justeras mot en gräns på 4 byte, vilket är mindre än den gräns på 8 byte som anges av fältet 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
Om du vill ta ett annat exempel bör du överväga följande struktur, som består av två bytefält, ett 32-bitars signerat heltalsfält, en bytematris med ett enda element och ett decimalvärde. Med standardstorleken för förpackning är strukturens storlek 28 byte i .NET Framework och 32 byte i .NET 5+. De två byteen upptar de två första byteen minne följt av två byte utfyllnad, följt av heltal. Nästa är matrisen med en byte, följt av tre byte utfyllnad. Eftersom ett decimalvärde består av flera fält baseras justeringen på det största av dess fält i stället för strukturens storlek Decimal som helhet. I .NET 5 och senare versioner består strukturen Decimal av två Int32 fält och ett fält på 8 byte, så Decimal fält, d5, justeras mot en gräns på 8 byte. I .NET Framework består Decimal-strukturen av fyra Int32 fält, så fältet Decimal, d5, justeras mot en gräns på 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
Om Pack är inställt på 2 är strukturens storlek 24 byte. Jämfört med standardjusteringen har de två byteen med utfyllnad mellan de två byteen och heltal tagits bort eftersom typens justering nu är 4 i stället för 2. Och de tre byteen av utfyllnad efter a4 har ersatts med en byte utfyllnad, eftersom d5 nu justeras på en gräns på 2 byte i stället för en 4-bytesgräns.
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
Om Pack är inställt på 16 är strukturens storlek densamma som i standardfallet, eftersom alla justeringskrav i den här strukturen är mindre än 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
Fältet Pack används ofta när strukturer exporteras under disk- och nätverksskrivningsåtgärder. Fältet används också ofta under plattformsanrop och interop-åtgärder.
Ibland används fältet för att minska minneskraven genom att producera en snävare förpackningsstorlek. Den här användningen kräver dock noggrant övervägande av faktiska maskinvarubegränsningar och kan faktiskt försämra prestanda.