C#은 기본적으로 StructLayout 가 정해져 있습니다.

클래스는 [StructLayout(LayoutKind.Auto, Pack = 0)]

구조체는 [StructLayout(LayoutKind.Sequential, Pack =0)]

 

평소엔 신경쓰지 않아도 되지만 C, C++ 혹은 서버와 통신 등 메모리를 맞춰줘야 될 때

사용되는 기능이니 이런 것이 있다는 것만 알면 될거 같습니다.

아래 코드는 C#으로 C, C++ 포인터를 흉내내어 메모리 참조를 해본 코드입니다.

 

using System;
using System.Runtime.InteropServices; // [StructLayout ] 선언에 필요합니다.

//참고 설명 https://www.csharpstudy.com/DevNote/Article/10

//*****************************************************************
//
//  기본값
//  class  : [StructLayout(LayoutKind.Auto, Pack = 0)]
//  struct : [StrcutLayout(LayoutKind.Sequential, Pack = 0)]
//
//  Pack : 0이면 자동 세팅에 따릅니다. (0, 1, 2, 4, 8, 16... 128 까지 2의 배수만 가능합니다.)
//         1 이상이면 Pack과 타입 크기 중 가장 큰 단위에 따라 패딩을 넣어줍니다.
//      
//  ex)
//      [StructLayout(LayoutKind.Sequential, Pack = 0)]
//      struct MyStruct
//      {
//          public int i;     // 4
//          public double d;  // 8
//          public byte b;    // 1
//      }
//
//      가장 큰 사이즈에 맞추어 크기가 조절 됩니다.
//      Pack = 0 이면 가장 큰 사이즈 byte
//      sizeof(MyStruct) == 24
//      
//      i  = (0~3)
//    패딩 = (4~7)
//      d  = (8~15)
//      b  = (16)
//    패딩 = (17~23)
//
//      Pack = 1 이면 1에 가까운 타입에 맞추어집니다. 즉 byte 중심이 되며
//      i = (0~3), d = (4~11), b = (12) 가 되어 0~12까지 size = 13이 됩니다.
//
// LayoutKind.Sequential    : 메모리상에 순차적으로 저장합니다.
//            Auto          : 힙 영역에 자동으로 저장합니다.
//            Explicit      : 직접 메모리 영역을 지정해줍니다.
//                            변수에 [FieldOffset()] 식으로 지정해주어야 합니다.
//
//****************************************************************


namespace StructLayout
{
    class Program
    {
        [StructLayout(LayoutKind.Explicit, Pack = 1)] //int형 4에 맞춰집니다.
        public struct Test
        {
            [FieldOffset(0)]
            public int value; // 4 (0000 0000, 0000 0000, 0000 0000, 0000 0000)

            [FieldOffset(0)]
            public byte value1; // (0000 0000 ____ ____ ____ ____ ____ ____)

            [FieldOffset(1)]
            public byte value2; // (____ ____ 0000 0000 ____ ____ ____ ____)

            [FieldOffset(2)]
            public byte value3; // (____ ____ ____ ____ 0000 0000 ____ ____)

            [FieldOffset(3)]
            public byte value4; // (____ ____ ____ ____ ____ ____ 0000 0000)
        }

        //c언어의 포인터를 흉내낼 수 있습니다!
        static unsafe void Main(string[] args) //unsafe : 포인터 사용지 설정이 필요합니다.
        {
            Test test = new Test();

            Console.WriteLine("sizeof(TEST) : {0}", sizeof(Test));

            //c, c++언어의 포인터
            int* startAddress = (int*)&test;

            //1100 1100, 0000 0100, 0000 0001, 0000 0001
            test.value = (1 << 31) | (1 << 30) | (1 << 28) | (1 << 27) | //1100 1100 ____ ____ ____ ____ ____ ____
                         (1 << 18) |                                     //1100 1100 0000 0100 ____ ____ ____ ____
                         (1 << 8)  |                                     //1100 1100 0000 0100 0000 0001 ____ ____
                         1;                                              //1100 1100 0000 0100 0000 0001 0000 0001

            Console.WriteLine("test.value : {0}", Convert.ToString(test.value, 2)); //2진수로 출력
            Console.WriteLine("test.value1 : {0}", Convert.ToString(test.value1, 2)); //2진수로 출력 0000 0001
            Console.WriteLine("test.value3 : {0}", Convert.ToString(test.value2, 2)); //2진수로 출력 0000 0001
            Console.WriteLine("test.value2 : {0}", Convert.ToString(test.value3, 2)); //2진수로 출력 0000 0100
            Console.WriteLine("test.value4 : {0}", Convert.ToString(test.value4, 2)); //2진수로 출력 1100 1100
        }
    }
}

 

 

결과 값 2진수로 표현하였고 앞의 0은 사라집니다.

 

+ Recent posts