StructLayoutAttribute.Pack Campo

Definição

Controla o alinhamento dos campos de dados de uma classe ou estrutura na memória.

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

Valor do campo

Comentários

O Pack campo controla o alinhamento dos campos de um tipo na memória. Ele afeta LayoutKind.Sequential. Por padrão, o valor é 0, indicando o tamanho de empacotamento padrão para a plataforma atual. O valor de Pack deve ser 0, 1, 2, 4, 8, 16, 32, 64 ou 128:

Os campos de uma instância de tipo são alinhados usando as seguintes regras:

  • O alinhamento do tipo é o tamanho de seu maior elemento (1, 2, 4, 8 etc., bytes) ou o tamanho de empacotamento especificado, o que for menor.

  • Cada campo deve se alinhar com campos de seu próprio tamanho (1, 2, 4, 8 etc., bytes) ou o alinhamento do tipo, o que for menor. Como o alinhamento padrão do tipo é o tamanho de seu maior elemento, que é maior ou igual a todos os outros comprimentos de campo, isso geralmente significa que os campos são alinhados pelo seu tamanho. Por exemplo, mesmo que o maior campo em um tipo seja um inteiro de 64 bits (8 bytes) ou o campo Pacote esteja definido como 8, Byte os campos se alinham em limites de 1 byte, Int16 os campos se alinham em limites de 2 bytes e Int32 os campos se alinham em limites de 4 bytes.

  • O preenchimento é adicionado entre campos para atender aos requisitos de alinhamento.

Por exemplo, considere a estrutura a seguir, que consiste em dois Byte campos e um Int32 campo, quando ela é usada com vários valores para o Pack campo.

using System;

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

Importante

Para compilar com êxito os exemplos de C#, você deve especificar a opção do /unsafe compilador.

Se você especificar o tamanho de empacotamento padrão, o tamanho da estrutura será de 8 bytes. Os dois bytes ocupam os dois primeiros bytes de memória, pois os bytes devem se alinhar em limites de um byte. Como o alinhamento padrão do tipo é de 4 bytes, que é o tamanho de seus campos maiores, i3, há dois bytes de preenchimento seguidos pelo campo inteiro.

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=0)]
struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct ex = new ExampleStruct();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct));
      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 for definido como 2, o tamanho da estrutura será de 6 bytes. Como antes, os dois bytes ocupam os dois primeiros bytes de memória. Como os campos agora se alinham em limites de 2 bytes, não há preenchimento entre o segundo byte e o inteiro.

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=2)]
struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct ex = new ExampleStruct();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct));
      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 for definido como 4, o tamanho da estrutura será o mesmo que no caso padrão, em que o alinhamento do tipo foi definido pelo tamanho de seu campo maior, i3, que é 4.

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=4)]
struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct ex = new ExampleStruct();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct));
      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 for definido como 8, o tamanho da estrutura ainda será o mesmo que no caso padrão, pois o i3 campo se alinha em um limite de 4 bytes, que é menor que o limite de 8 bytes especificado pelo campo Pacote.

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=8)]
struct ExampleStruct
{
   public byte b1;
   public byte b2;
   public int i3;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct ex = new ExampleStruct();
      byte* addr = (byte*) &ex;
      Console.WriteLine("Size:      {0}", sizeof(ExampleStruct));
      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

Para tomar outro exemplo, considere a estrutura a seguir, que consiste em dois campos de byte, um campo inteiro com sinal de 32 bits, uma matriz de bytes de elemento único e um valor decimal. Com o tamanho de empacotamento padrão, o tamanho da estrutura é de 28 bytes. Os dois bytes ocupam os dois primeiros bytes de memória, seguidos por dois bytes de preenchimento, seguidos pelo inteiro. Em seguida, está a matriz de um byte, seguida por três bytes de preenchimento. Por fim, o Decimal campo d5 se alinha em um limite de 4 bytes porque um valor decimal consiste em quatro Int32 campos, de modo que seu alinhamento é baseado no tamanho do maior de seus campos em vez do tamanho da Decimal estrutura como um todo.

using System;
using System.Runtime.InteropServices;

unsafe struct ExampleStruct2
{

   public byte b1;
   public byte b2;
   public int i3;
   public fixed byte a4[1];
   public decimal d5;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct2 ex = new ExampleStruct2();
      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);
      Console.WriteLine("a4 Offset: {0}", ex.a4 - addr);
      Console.WriteLine("d5 Offset: {0}", (byte*) &ex.d5 - addr);
   }
}
// The example displays the following output:
//       Size:      28
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4
//       a4 Offset: 8
//       d5 Offset: 12

Se Pack for definido como 2, o tamanho da estrutura será de 24 bytes. Em comparação com o alinhamento padrão, os dois bytes de preenchimento entre os dois bytes e o inteiro foram removidos porque o alinhamento do tipo agora é 4 em vez de 2. E os três bytes de preenchimento depois a4 foram substituídos por um byte de preenchimento, já que d5 agora se alinha em um limite de 2 bytes em vez de um limite de 4 bytes.

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 2)]
unsafe struct ExampleStruct2
{

   public byte b1;
   public byte b2;
   public int i3;
   public fixed byte a4[1];
   public decimal d5;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct2 ex = new ExampleStruct2();
      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);
      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 for definido como 8, o tamanho da estrutura será o mesmo que no caso padrão, pois todos os requisitos de alinhamento nessa estrutura são menores que 8.

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 8)]
unsafe struct ExampleStruct2
{

   public byte b1;
   public byte b2;
   public int i3;
   public fixed byte a4[1];
   public decimal d5;
}

public class Example
{
   public unsafe static void Main()
   {

      ExampleStruct2 ex = new ExampleStruct2();
      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);
      Console.WriteLine("a4 Offset: {0}", ex.a4 - addr);
      Console.WriteLine("d5 Offset: {0}", (byte*) &ex.d5 - addr);
   }
}
// The example displays the following output:
//       Size:      28
//       b1 Offset: 0
//       b2 Offset: 1
//       i3 Offset: 4
//       a4 Offset: 8
//       d5 Offset: 12

O Pack campo é frequentemente usado quando as estruturas são exportadas durante operações de gravação de disco e rede. O campo também é frequentemente usado durante operações de invocação e interoperabilidade de plataforma.

Ocasionalmente, o campo é usado para reduzir os requisitos de memória produzindo um tamanho de empacotamento mais apertado. No entanto, esse uso requer uma consideração cuidadosa das restrições reais de hardware e pode realmente prejudicar o desempenho.

Aplica-se a