StructLayoutAttribute.Pack 필드

정의

메모리에 있는 클래스 또는 구조체의 데이터 필드 맞춤을 제어합니다.

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

필드 값

설명

Pack 필드는 메모리에서 형식의 필드 맞춤을 제어합니다. 에 영향을 줍니다 LayoutKind.Sequential. 기본적으로 값은 0이며 현재 플랫폼의 기본 압축 크기를 나타냅니다. 값 Pack 은 0, 1, 2, 4, 8, 16, 32, 64 또는 128이어야 합니다.

instance 형식의 필드는 다음 규칙을 사용하여 정렬됩니다.

  • 형식의 맞춤은 가장 큰 요소의 크기(1, 2, 4, 8 등, 바이트) 또는 지정된 압축 크기 중 더 작은 크기입니다.

  • 각 필드는 자체 크기의 필드(1, 2, 4, 8 등) 또는 형식의 맞춤 중 더 작은 필드와 일치해야 합니다. 형식의 기본 맞춤은 다른 모든 필드 길이보다 크거나 같은 가장 큰 요소의 크기이므로 일반적으로 필드가 크기에 따라 정렬됨을 의미합니다. 예를 들어 형식에서 가장 큰 필드가 64비트(8 바이트) 정수이거나 Pack 필드가 8 Byte 로 설정된 경우에도 필드는 1 바이트 경계 Int16 에 맞춰지고 필드는 2 바이트 경계에 정렬되고 Int32 필드는 4 바이트 경계에 정렬됩니다.

  • 맞춤 요구 사항을 충족하기 위해 필드 사이에 안쪽 여백이 추가됩니다.

예를 들어 필드에 대한 다양한 값 Pack 과 함께 사용되는 경우 두 Byte 개의 필드와 하나의 Int32 필드로 구성된 다음 구조를 고려해 보세요.

using System;

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

중요

C# 예제를 성공적으로 컴파일하려면 컴파일러 스위치를 /unsafe 지정해야 합니다.

기본 압축 크기를 지정하는 경우 구조체의 크기는 8바이트입니다. 바이트는 1바이트 경계에 맞춰야 하므로 두 바이트는 메모리의 처음 두 바이트를 차지합니다. 형식의 기본 맞춤은 가장 큰 필드 i3의 크기인 4바이트이므로 2바이트의 안쪽 여백과 정수 필드가 있습니다.

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

가 2로 설정된 경우 Pack 구조체의 크기는 6바이트입니다. 이전과 마찬가지로 두 바이트는 처음 두 바이트의 메모리를 차지합니다. 이제 필드가 2바이트 경계에 맞춰지므로 두 번째 바이트와 정수 사이에 안쪽 여백이 없습니다.

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

가 4로 설정된 경우 Pack 구조체의 크기는 기본 사례와 동일합니다. 여기서 형식의 맞춤은 가장 큰 필드의 크기( i34)로 정의되었습니다.

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

가 8로 설정된 경우 Pack 필드가 Pack 필드에 지정된 8 바이트 경계보다 작은 4 바이트 경계에 맞춰지므로 구조체의 크기는 기본 사례 i3 와 동일합니다.

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

또 다른 예를 들어 두 바이트 필드, 32비트 부속 정수 필드 1개, 단일 요소 바이트 배열 1개 및 10진수 값으로 구성된 다음 구조를 고려해 보세요. 기본 압축 크기의 구조체 크기는 28바이트입니다. 두 바이트는 처음 2바이트의 메모리를 차지하고 그 뒤에 2바이트의 안쪽 여백과 정수가 잇습니다. 다음은 1바이트 배열과 3바이트의 안쪽 여백입니다. 마지막으로 Decimal 10진수 값은 4개의 Int32 필드로 구성되므로 필드 d5는 4 바이트 경계에 맞춰지므로 전체 구조체의 크기가 아닌 필드의 가장 큰 크기에 Decimal 따라 정렬됩니다.

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

가 2로 설정된 경우 Pack 구조체의 크기는 24바이트입니다. 기본 맞춤과 비교하여 형식의 맞춤이 이제 2가 아닌 4이므로 두 바이트와 정수 사이의 패딩 2바이트가 제거되었습니다. 그리고 이후 a4 패딩의 세 바이트는 안쪽 여백의 1 바이트로 대체되었습니다, d5 이후 지금은 4 바이트 경계가 아닌 2 바이트 경계에 정렬.

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

가 8로 설정된 경우 Pack 이 구조체의 모든 맞춤 요구 사항이 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

Pack 필드는 디스크 및 네트워크 쓰기 작업 중에 구조를 내보낼 때 자주 사용됩니다. 이 필드는 플랫폼 호출 및 interop 작업 중에도 자주 사용됩니다.

경우에 따라 필드는 더 엄격한 압축 크기를 생성하여 메모리 요구 사항을 줄이는 데 사용됩니다. 그러나 이 사용은 실제 하드웨어 제약 조건을 신중하게 고려해야 하며 실제로 성능이 저하할 수 있습니다.

적용 대상