상세 컨텐츠

본문 제목

[C#] Sizeof, Marshal.SizeOf Method 형 크기 SizeOf 관련

본문

반응형
728x170

 

 

 

 

=================================

=================================

=================================

 

 

 

 

 

 

 

출처: https://docs.microsoft.com/ko-kr/dotnet/api/system.runtime.interopservices.marshal.sizeof?view=netframework-4.7.2

 

클래스의 관리되지 않는 크기(바이트)를 반환합니다.

오버로드

SizeOf(Object) 개체의 관리되지 않는 크기(바이트)를 반환합니다.
SizeOf(Type) 관리되지 않는 형식의 크기(바이트)를 반환합니다.
SizeOf<T>() [.NET Framework 4.5.1 이상 버전에서 지원됨] 관리되지 않는 형식의 크기(바이트)를 반환합니다.
SizeOf<T>(T) [.NET Framework 4.5.1 이상 버전에서 지원됨] 지정된 형식의 개체의 관리되지 않은 크기를 반환합니다(바이트 단위).

SizeOf(Object)

경고

이 API는 현재 사용되지 않습니다.

개체의 관리되지 않는 크기(바이트)를 반환합니다.

C#
[System.Runtime.InteropServices.ComVisible(true)] [System.Obsolete("SizeOf(Object) may be unavailable in future releases. Instead, use SizeOf<T>(). For more info, go to http://go.microsoft.com/fwlink/?LinkID=296514")] public static int SizeOf (object structure);

매개 변수

structure
Object

크기가 반환되는 개체입니다.

반환

비관리 코드에서 지정된 개체의 크기입니다.

예외

structure 매개 변수가 null인 경우

예제

다음 예제에서는 관리 되는 구조를 만듭니다, 그리고 관리 되지 않는 메모리 전송 및 관리 되는 메모리에 다시 전송 합니다.이 예제에서는 SizeOf 할당할 관리 되지 않는 메모리 양을 확인 하는 방법입니다.

C#
using System; using System.Runtime.InteropServices;  public struct Point {     public int x;     public int y; }  class Example {      static void Main()     {          // Create a point struct.         Point p;         p.x = 1;         p.y = 1;          Console.WriteLine("The value of first point is " + p.x + " and " + p.y + ".");          // Initialize unmanged memory to hold the struct.         IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(p));          try         {              // Copy the struct to unmanaged memory.             Marshal.StructureToPtr(p, pnt, false);              // Create another point.             Point anotherP;              // Set this Point to the value of the              // Point in unmanaged memory.              anotherP = (Point)Marshal.PtrToStructure(pnt, typeof(Point));              Console.WriteLine("The value of new point is " + anotherP.x + " and " + anotherP.y + ".");          }         finally         {             // Free the unmanaged memory.             Marshal.FreeHGlobal(pnt);         }                }  } 

설명

이 메서드는 boxed 값 형식 또는 참조 형식이 될 수 있는 구조체의 인스턴스를 허용 합니다. 레이아웃이 sequential 또는 explicit 이어야 합니다.

반환 되는 크기는 관리 되지 않는 개체의 크기가입니다. 개체의 비관리 및 관리 되는 크기를 다를 수 있습니다. 문자 형식의 크기는 영향을 받지는 CharSet 클래스에 적용 되는 값입니다.

사용할 수는 SizeOf 메서드를 사용 하 여 할당할 관리 되지 않는 메모리 양을 확인 합니다 AllocHGlobal 및 AllocCoTaskMem메서드.

추가 정보

SizeOf(Type)

경고

이 API는 현재 사용되지 않습니다.

관리되지 않는 형식의 크기(바이트)를 반환합니다.

C#
[System.Obsolete("SizeOf(Type) may be unavailable in future releases. Instead, use SizeOf<T>(). For more info, go to http://go.microsoft.com/fwlink/?LinkID=296515")] public static int SizeOf (Type t);

매개 변수

t
Type

크기가 반환되는 형식입니다.

반환

비관리 코드에서 지정된 형식의 크기입니다.

예외

t 매개 변수는 제네릭 형식 정의입니다.

t 매개 변수가 null인 경우

예제

다음 예제에서는 SizeOf 메서드를 호출하는 방법을 보여 줍니다. 이 코드 예제는에 대해 제공 된 큰 예제의 일부는 Marshal클래스입니다.

C#
// Demonstrate the use of the SizeOf method of the Marshal class. Console.WriteLine("Number of bytes needed by a Point object: {0}",      Marshal.SizeOf(typeof(Point))); Point p = new Point(); Console.WriteLine("Number of bytes needed by a Point object: {0}",     Marshal.SizeOf(p)); 

설명

구조를 없는 경우이 메서드를 사용할 수 있습니다. 레이아웃이 sequential 또는 explicit 이어야 합니다.

반환 되는 크기는 관리 되지 않는 형식의 크기가입니다. 개체의 비관리 및 관리 되는 크기를 다를 수 있습니다. 문자 형식의 크기는 영향을 받지는 CharSet 클래스에 적용 되는 값입니다.

추가 정보

SizeOf<T>()

[.NET Framework 4.5.1 이상 버전에서 지원됨] 관리되지 않는 형식의 크기(바이트)를 반환합니다.

C#
public static int SizeOf<T> ();

형식 매개 변수

T

크기가 반환되는 형식입니다.

반환

T 제네릭 형식 매개 변수로 지정된 형식의 크기(바이트 단위)입니다.

설명

구조를 없는 경우이 메서드를 사용할 수 있습니다. 레이아웃이 sequential 또는 explicit 이어야 합니다.

반환 되는 크기는 관리 되지 않는 형식의 크기가입니다. 개체의 비관리 및 관리 되는 크기를 다를 수 있습니다. 문자 형식의 크기는 영향을 받지는 CharSet 클래스에 적용 되는 값입니다.

SizeOf<T>(T)

[.NET Framework 4.5.1 이상 버전에서 지원됨] 지정된 형식의 개체의 관리되지 않은 크기를 반환합니다(바이트 단위).

C#
public static int SizeOf<T> (T structure);

형식 매개 변수

T

structure 매개 변수의 형식입니다.

매개 변수

structure
T

크기가 반환되는 개체입니다.

반환

비관리 코드에서 지정된 개체의 크기(바이트)입니다.

예외

structure 매개 변수가 null인 경우

설명

이 메서드는 boxed 값 형식 또는 참조 형식이 될 수 있는 구조체의 인스턴스를 허용 합니다. 레이아웃이 sequential 또는 explicit 이어야 합니다.

반환 되는 크기는 관리 되지 않는 개체의 크기가입니다. 개체의 비관리 및 관리 되는 크기를 다를 수 있습니다. 문자 형식의 크기는 영향을 받지는 CharSet 클래스에 적용 되는 값입니다.

사용할 수는 SizeOf<T>(T) 메서드를 사용 하 여 할당을 관리 되지 않는 메모리 양을 확인 합니다 AllocHGlobal 및 AllocCoTaskMem 메서드.

적용 대상

.NET Core

3.0 Preview 2 2.2 2.1 2.0 1.1 1.0

.NET Framework

4.8 4.7.2 4.7.1 4.7 4.6.2 4.6.1 4.6 4.5.2 4.5.1 4.5 4.0 3.5 3.0 2.0 1.1

.NET Standard

2.0 1.6 1.5 1.4 1.3 1.2 1.1

UWP

10.0

Xamarin.Android

7.1

Xamarin.iOS

10.8

Xamarin.Mac

3.0

 

 

=================================

=================================

=================================

 

 

 

반응형

 

728x90

 

 

 

출처: http://www.csharpstudy.com/DevNote/Article/10

 

 

[제목] 객체의 메모리 레이아웃에 대하여

클래스 혹은 구조체 객체의 크기는 일반적으로 필드 크기의 합보다 크게 표시되며, 객체의 필드들은 개발자가 정의한 순서대로 메모리 상에 위치하지 않는다. 이 노트는 이러한 현상의 이유와 해결법을 알아본다.

다음과 같은 구조체의 크기를 구해보자.

1 2 3 4 5 6 
struct MyStruct {     public int i;     // 4     public double d;  // 8     public byte b;    // 1 }

구조체의 크기는 각 필드 크기의 합이므로, 이론적으로 MyStruct 구조체의 크기는 4+8+1 = 13 이다. 크기를 구하기 위해 다음과 같이 Marshal.SizeOf()를 사용할 수 있다.

1 
int size = Marshal.SizeOf(typeof(MyStruct)); 

하지만 실제 이 문장을 실행해 보면, size가 24임을 알 수 있다. 이는 필드들을 메모리 바운더리 상에 정렬하는 Field Alignment 규칙에 따른 것이다. 즉, 위의 구조체의 경우 8바이트 바운더리에 맞춘 것이다. 이러한 Alignment는 C# / .NET에서 자동으로 처리되는데, 경우에 따라 개발자가 이를 변경할 필요가 있을 때가 있다. 예를 들어, 네트워크 스트림이나 파일 스트림에 위의 구조체가 정확히 13바이트로 존재해야 할 경우가 있을 수 있고, 또는 Unmanaged Code와 함께 데이타를 사용해야 할 경우가 있을 수 있다. 이러한 경우 정확한 Object 크기를 셋팅하기 위해 Pack이라는 속성을 지정할 수 있다. Pack=1은 1바이트로 정렬된다는 의미로 이를 지정하면 위의 MyStruct는 정확히 13 바이트를 갖게 된다.

아래 예제는 13 바이트의 구조체를 생성한 후 이를 바이너리 파일로 저장한 후, 파일 크기가 13 바이트임을 체크하는 코드이다.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 
[StructLayout(LayoutKind.Sequential, Pack = 1)] struct MyStruct {     public int i;     // 4     public double d;  // 8     public byte b;    // 1 }  static void Main(string[] args) {     int size = Marshal.SizeOf(typeof(MyStruct));     Console.WriteLine(size);      var s = new MyStruct();     s.i = 1;     s.d = 2;     s.b = 3;      byte[] buff = new byte[size];     IntPtr ptr = Marshal.AllocHGlobal(size);      Marshal.StructureToPtr(s, ptr, true);     Marshal.Copy(ptr, buff, 0, size);     Marshal.FreeHGlobal(ptr);      string filename = @"c:\temp\1.txt";     using (var fs = new FileStream(filename, FileMode.Create))     {         using (var wr = new BinaryWriter(fs))         {             wr.Write(buff);         }     }      byte[] bytes = File.ReadAllBytes(filename);     Console.WriteLine(bytes.Length); }


이렇게 크기의 문제가 해결되었어도 한가지 남는 문제가 있다. 즉, 각 필드의 순서가 서로 틀려서는 안된다는 것이다. CLR은 기본적으로 Optimiazation의 일환으로 클래스 필드의 순서를 자동으로 변경하는데 이것을 Auto Layout이라 부른다. Auto Layout은 Managed Memory 상에서 클래스 필드의 순서를 자동으로 재배치하는데, 이러한 타입의 레이아웃은 Managed 영역밖으로 데이타를 Export하지 못한다. 즉, 위와 같은 ( Marshal.* ) 마샬링 코드를 사용할 수 없다. 만약 마샬링을 사용하면 런타임 에러가 발생한다.

C#에서 클래스와 같은 Reference Type은 디폴트로 Auto Layout을 사용하고, Struct와 같은 Value Type은 디폴트로 Sequential Layout을 사용한다. Sequential Layout은 Managed Memory에서 마샬링을 사용해 Unmanaged Memory로 옮길 때 각 필드의 순서가 Unmanaged Memory에서 유지되는 레이아웃이다. 위의 예제에서 MyStruct구조체는 [StructLayout(LayoutKind.Sequential)]을 사용하고 있는데, 이는 Managed 메모리 영역에서는 순서가 어떨지 모르지만, Unmanaged Memory로 옮겨질 때는 반드시 필드 순서대로 데이타가 옮겨진다는 것을 의미한다.

그렇다면, Managed Memory에서도 필드 순서가 유지되도록 할 수 있을까? 이를 위해 마지막 레이아웃 타입인 Explicit Layout이 존재한다.이 레이아웃을 사용하면 클래스이든 구조체이든 상관없이 Managed Memory 상에서 필드에 지정된 FieldOffset() 속성에 따라 메모리 위치가 설정된다. 또한, 이 객체가 Unmanaged Memory로 옮겨질 때도 동일한 필드 위치를 유지하게 된다.

1 2 3 4 5 6 7 8 9 10 
[StructLayout(LayoutKind.Explicit, Pack = 1)] class MyClass {     [FieldOffset(0)]     public int i;     [FieldOffset(4)]     public double d;     [FieldOffset(12)]     public byte b; }

위의 코드는 MyClass 라는 클래스에 Explicit 레이아웃을 사용하여 필드 i 가 처음에, 필드 d가 4번째 바이트 위치에, 필드 b가 12번째에 각각 위치하게 됨을 지정하고 있다. 이러한 필드 위치는 Managed Heap에 MyClass객체가 생성될 때와 이 객체가 다시 Unmanaged Heap에 옮겨질 때 모두 그대로 유지된다.

 

 

=================================

=================================

=================================

 

 

 

 

출처: https://docs.microsoft.com/ko-kr/dotnet/api/system.runtime.interopservices.structlayoutattribute?view=netframework-4.7.2

 

 

StructLayoutAttribute Class

정의

메모리에 있는 클래스 또는 구조체의 데이터 필드에 대한 실제 레이아웃을 제어할 수 있습니다.

C#
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct, Inherited=false)] [System.Runtime.InteropServices.ComVisible(true)] public sealed class StructLayoutAttribute : Attribute
상속
StructLayoutAttribute
특성

예제

다음 예제에서는 관리 되는 선언 된 GetSystemTime 함수를 정의 MySystemTime 클래스와 LayoutKind.Explicit 레이아웃 합니다. GetSystemTime 콘솔 출력 및 시스템 시간을 가져옵니다.

C#
using System; using System.Runtime.InteropServices;  namespace InteropSample {        [StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]    public class MySystemTime     {       [FieldOffset(0)]public ushort wYear;        [FieldOffset(2)]public ushort wMonth;       [FieldOffset(4)]public ushort wDayOfWeek;        [FieldOffset(6)]public ushort wDay;        [FieldOffset(8)]public ushort wHour;        [FieldOffset(10)]public ushort wMinute;        [FieldOffset(12)]public ushort wSecond;        [FieldOffset(14)]public ushort wMilliseconds;     }     class LibWrapper    {       [DllImport("kernel32.dll")]       public static extern void GetSystemTime([MarshalAs(UnmanagedType.LPStruct)]MySystemTime st);    };     class TestApplication    {             public static void Main()       {          try          {             MySystemTime sysTime = new MySystemTime();             LibWrapper.GetSystemTime(sysTime);             Console.WriteLine("The System time is {0}/{1}/{2} {3}:{4}:{5}", sysTime.wDay,                sysTime.wMonth, sysTime.wYear, sysTime.wHour, sysTime.wMinute, sysTime.wSecond);                      }                   catch(TypeLoadException e)          {             Console.WriteLine("TypeLoadException : " + e.Message);          }          catch(Exception e)          {             Console.WriteLine("Exception : " + e.Message);          }       }    } } 

설명

이 특성은 클래스 또는 구조체에 적용할 수 있습니다.

공용 언어 런타임 클래스 또는 구조체의 관리 되는 메모리의 데이터 필드에 대 한 실제 레이아웃을 제어합니다. 그러나 형식을 관리 되지 않는 코드에 전달 하려는 경우 사용할 수는 StructLayoutAttribute 특성 형식의 관리 되지 않는 레이아웃을 제어 합니다. 특성을 사용 하 여 LayoutKind.Sequential 멤버가 나타나는 순서 대로 순차적으로 배치 합니다. Blittable 형식에 대 한 LayoutKind.Sequential 모두 관리 되는 메모리의 레이아웃 및 관리 되지 않는 메모리의 레이아웃을 제어 합니다. 비 blittable 형식에 대 한 경우 클래스 또는 구조체 비관리 코드로 마샬링될 관리 되는 메모리의 레이아웃을 제어 하지는 않습니다 레이아웃을 제어 합니다. 특성을 사용 하 여 LayoutKind.Explicit 각 데이터 멤버의 정확한 위치를 제어 합니다. 이 모두 blittable 형식 및 비 blittable 형식에 대 한 관리 및 비관리 레이아웃을 영향을 줍니다. 사용 하 여 LayoutKind.Explicit 사용을 요구 하는FieldOffsetAttribute 형식 내에서 각 필드의 위치를 나타내는 특성입니다.

C#, Visual Basic 및 c + + 컴파일러에서 적용 된 Sequential 기본적으로 구조 레이아웃 값입니다. 클래스를 적용 해야 합니다는 LayoutKind.Sequential 값을 명시적으로 합니다. Tlbimp.exe (형식 라이브러리 가져오기) 도 적용 됩니다는StructLayoutAttribute 특성; 항상 적용 됩니다는 LayoutKind.Sequential 형식 라이브러리를 가져올 때 값입니다.

 

 

 

=================================

=================================

=================================

 

 

 

출처: https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/sizeof

 

 

sizeof(C# 참조)

관리되지 않는 형식의 크기(바이트)를 가져오는 데 사용됩니다.

관리되지 않는 형식은 다음과 같습니다.

  • 다음 표에서는 간단한 형식을 보여 줍니다.
  • 상수 값
    sizeof(sbyte) 1
    sizeof(byte) 1
    sizeof(short) 2
    sizeof(ushort) 2
    sizeof(int) 4
    sizeof(uint) 4
    sizeof(long) 8
    sizeof(ulong) 8
    sizeof(char) 2(유니코드)
    sizeof(float) 4
    sizeof(double) 8
    sizeof(decimal) 16
    sizeof(bool) 1
  • 열거형 형식.
  • 포인터 형식.
  • 참조 형식 또는 구성된 형식인 모든 인스턴스 필드 또는 자동 구현 인스턴스 속성을 포함하지 않는 사용자 정의 구조체입니다.

다음 예제에서는 int의 크기를 검색하는 방법을 보여 줍니다.

C#
// Constant value 4: int intSize = sizeof(int); 

설명

C# 버전 2.0부터 단순 형식 또는 열거형 형식에 sizeof를 적용하면 안전하지 않은 컨텍스트에서 코드를 더 이상 컴파일할 필요가 없습니다.

sizeof 연산자를 오버로드할 수 없습니다. sizeof 연산자에서 반환되는 값은 int 형식입니다. 이전 표에서는 특정 단순 형식이 피연산자로 포함된 sizeof 식을 대체하는 상수 값을 보여 줍니다.

구조체를 비롯한 다른 모든 형식의 경우 sizeof 연산자는 안전하지 않은 코드 블록에서만 사용할 수 있습니다. Marshal.SizeOf메서드를 사용할 수 있지만 이 메서드에서 반환된 값이 sizeof에서 반환된 값과 항상 같지는 않습니다. Marshal.SizeOf는 형식이 마샬링된 후의 크기를 반환하는 반면, sizeof는 안쪽 여백을 포함하여 공용 언어 런타임에 의해 할당된 크기를 반환합니다.

C#
class MainClass {     // unsafe not required for primitive types     static void Main()     {         Console.WriteLine("The size of short is {0}.", sizeof(short));         Console.WriteLine("The size of int is {0}.", sizeof(int));         Console.WriteLine("The size of long is {0}.", sizeof(long));     } } /* Output:     The size of short is 2.     The size of int is 4.     The size of long is 8. */ 

C# 언어 사양

자세한 내용은 C# 언어 사양을 참조하세요. C# 언어 사양은 C# 구문 및 사용법에 대한 신뢰할 수 있는 소스입니다.

참고 항목

 

 

 

=================================

=================================

=================================

 

 

 

출처: https://stackoverflow.com/questions/42438397/why-the-size-of-struct-a-is-not-equal-size-of-struct-b-with-same-fields/42438700

 

There are some paddings among fields. Padding is calculated using previous fields and next field.

Also, this condition should be true:

(size of struct) % (size of largest type) == 0

In your case the largest type is int and its size is 4 bytes.

struct A {     char a; // size is 2, no previous field, next field size is 2 - no alignment needed     char c; // size is 2, previous size is 2 -> 2 + 2 = 4, next size is 4 - no alignment needed     int b;  //size is 4, it is last field, size is 4 + 4 = 8.        //current size is 2 + 2 + 4 = 8     //8 % 4 == 0 - true - 8 is final size }  struct B {     char a; // size is 2, next size is 4, alignment needed - 2 -> 4, size of this field with alignment is 4     int b;  // size is 4, previous is 4, next size is 2(lower) - no alignment needed     char c; // size is 2, previous is 4 + 4 = 8 - no alignment needed      //current size is 4 + 4 + 2 = 10     //but size should be size % 4 = 0 -> 10 % 4 == 0 - false, adjust to 12 }

If you want same size for two structs you can use LayoutKind.Explicit:

[StructLayout(LayoutKind.Explicit)] public struct A {     [FieldOffset(0)]     char a;      [FieldOffset(2)]     char c;      [FieldOffset(4)]     int b; }  [StructLayout(LayoutKind.Explicit)] public struct B {     [FieldOffset(0)]     char a;      [FieldOffset(2)]     int b;      [FieldOffset(6)]     char c; }

OR

You can use LayoutKind.SequentialPack = 1 and CharSet = CharSet.Unicode to get size 8.

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct A {     char a;     char c;     int b; }  [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct B {             char a;     int b;     char c; }

Also, you can get struct size without unsafe:

Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(typeof(A))); Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(typeof(B)));

 

 

 

=================================

=================================

=================================

 

 

 

 

반응형
그리드형


관련글 더보기

댓글 영역