bdfgdfg

[C#] C#의 데이터 형식 본문

게임프로그래밍/C#

[C#] C#의 데이터 형식

marmelo12 2022. 4. 17. 15:28
반응형

C#에는 '값' 형식과 '참조' 형식 두가지가 존재한다.

 

값 형식과 참조 형식

값 형식은 벼누가 값을 담는 데이터 형식을 말하고, 참조 형식은 변수가 값 대신 해당 값이 있는 곳의 위치(참조)를 담는 데이터 형식.

값 형식의 데이터는 스택 메모리 영역에 올라가며 참조 형식의 데이터는 힙 메모리 영역에 올라간다.

 -> 참조 변수(스택 영역에 존재)가 힙 메모리 영역에 있는 해당 값을 가리키는 것.

 

기본적으로 힙 메모리 영역에 올라가는 데이터는 사용자가 직접 동적할당 하는 메모리 영역이다.

 -> C++에서는 사용자가 동적할당했으면 직접 메모리를 해제 해야한다. (혹은 RAII패턴이 적용된 스마트 포인터를 이용)

 -> 즉 힙 메모리 영역에 올라간 데이터는 기본적으로 자기 스스로 제거하는 매커니즘은 아닌 것.

 

대신 C#은 C++과는 달리 동적할당된(힙 메모리 영역에 있는 메모리) 메모리를 직접 해제하지 않아도 된다.

앞서 배운 CLR의 가비지 컬렉터를 통해 힙에 더 이상 사용되지 않는(참조되지 않는) 객체가 있으면 그 객체를 쓰레기(가비지)로 간주하고 해당 메모리를 해제(수거)하는 역할을 한다.

 -> 실제로는 바로 수거해 가지는 않는다.

https://aroundck.tistory.com/664

실제로 C#에서 레퍼런스(참조) 변수인 Object 자료형을 이용해 힙 메모리에 데이터를 각각 10,20을 저장해보면

위 그림과 같이 참조 변수는 스택 영역에. 해당 참조 변수가 가리키는 실제 데이터의 위치에 각각 값을 저장한다.

 

Object 형식

Object 형식은 어떤 물건(데이터)이든지 담을 수 있는 데이터 형식이다.

C#은 Object가 모든 데이터를 다룰 수 있도록 '상속'이라는 특별한 조치를 취했다.

C#의 모든 자료형은(사용자가 직접 만든 Class,Struct또한) 모두 자동으로 Object 형식으로부터 상속받게 한다.

츨처 - http://aloloever.blogspot.com/2015/01/c-object-learn-to-type-object-in-c.html

그렇기에 컴파일러는 어떤 형식의 데이터라도 Object에 담아 처리할 수 있게 된다.

class Test
{
    public int a = 10;
}

class Program
{
    static void Main(string[] args)
    {
        Object a = new Test();
        Object b = 123;
        Object c = '마';
        Object d = 3.14f;
        Object e = "문자열 데이터";

        Test t = (Test)a;
        Console.WriteLine(t.a);
        Console.WriteLine(b);
        Console.WriteLine(c);
        Console.WriteLine(d);
        Console.WriteLine(e);


    }
}

정말 Object형식은 모든 데이터를 다 담는다.

 

박싱(Boxing)과 언박싱(Unboxing)

Object형식은 참조 형식이기에 힙에 데이터를 할당한다.

즉. Object형식에 값 타입의 데이터를 저장해도 힙 영역에 해당 값이 저장이 된다는 의미.

Object형식은 값 형식의 데이터를 힙에 할당하기 위한 "박싱(Boxing)"기능을 제공한다.

 -> 값 형식의 데이터를 할당하려는 시도가 이루어지면 Object형식은 박싱을 수행해 해당 데이터를 힙에 할당.

 

반대로 참조 형식의 데이터를 값 형식으로 변환하는 것을 "언박싱(UnBoxing)"이라 한다.

 

주의해야할것은 모든 객체가 값 형식으로 언박싱 될 수는 없다.

 -> 이전에 값 형식을 박싱하여 생성된 객체에 한해 언박싱이 가능하다.

또한 언박싱은 박싱하기 전 형식(자료형)을 준수해야 한다.

보통 캐스팅에서 short->int와 같이 더 큰 자료형으로의 형변환은 묵시적으로 일어나며 가능한 형 변환이다.

 

하지만 박싱/언박싱에서는 위와 같이 short타입을 박싱하고 int타입으로 언박싱은 불가능.

 

Object형식을 이용한 박싱/언박싱은 겉으로는 편리해보이나 비용이 꽤나 많이드는 작업이다.

MSDN에서 값 형식을 Boxing할 때 할당 작업보다 20배는 걸리는 시간이 걸리며, unBoxing을 할때에는 캐스팅에 걸리는 시간보다 4배이상의 시간이 걸린다고 한다.

 

이러한 Object는 특히 배열에서 정말 여러 타입을 저장한다고 할 때, 유용하게 쓰일 수 있지만 그에 대한 성능하락은 본인의 책임.

 -> 즉 최대한 사용을 지양해야 한다.

 -> 사실 편리하긴 하다. Object의 GetType함수를 이용해 우리가 해당 객체의 박싱이 일어나기전 타입을 기억할 필요도 없다.

 

Nullable 형식

프로그래밍을 하다 보면 어떤 값도 가지지않는 변수가 필요하다. (0이아닌 비어 있는 변수)

즉 변수에게 할당된 메모리 공간을 비워둘 수 있도록 Nullable 형식을 사용하면 된다

Nullable 형식의 변수를 선언할 때는 다음과 같이 원래 데이터 형식 이름뒤에 '?'만 붙여주면 된다.

int형 변수는 null이라는 값을 가질 수 없는 데이터 형식.

 -> C++의 nullptr과 유사하다. (즉 NULL이라는 매크로 정수 0값이 아니란 의미)

또한 nullable 형식의 변수는 멤버로 HasValue라는 프로퍼티(나중에 나옴)를 가지는데, 만약 아직 null값을 들고있다면 false를 내뱉으며 그 외에 값을 가지고 있다면 true를 반환한다.

혹은 b.Value를 통해 값을 추출할 수 있다.

var 타입

C#의 var는 C++ auto와 유사하다.

C++의 auto도 컴파일 타입에 해당 타입을 결정하게 되는데 var도 똑같다.

 -> 즉 런타임의 성능에 영향을 미치지 않음.

 

참고로 var는 지역 변수로만 사용할 수 있다.

 -> 클래스의 필드,전역변수 등

 

var형식과 object형식이 비슷해보일지는 모르겠지만

object형식은 값 타입의 데이터를 박싱하고 나중에 사용할 때 언박싱을 거쳐 사용하는 것이고,

var는 단순히 컴파일 타임에 해당 데이터의 자료형을 알아보고 결정하기에 CLR이 신경쓸 일은 없다.

 

 

반응형

'게임프로그래밍 > C#' 카테고리의 다른 글

[C#] 부모 자식 사이의 형 변환 (is,as)  (0) 2022.04.18
[C#] ref,out 키워드  (0) 2022.04.18
[C#] 문자열 다루기  (0) 2022.04.18
[C#] CLR(Common Language Runtime)  (0) 2022.04.17
Reflection / Attribute  (0) 2021.08.06
Comments