Learning
When: 1학년 10월 19일
How:
'이것이 C#이다'라는 책에서 초반에 배우는 내용인데, 이것을 보았을 때는 값 형식과 참조 형식도
제대로 몰랐기 때문에 제대로 공부하지 못했고, IEnumerator에 대해 배우다가 이 개념이 나와서
다시 공부하게 되었습니다.
Understanding:
- 간단 설명: 박싱과 언박싱은 object 형식과 밀접한 관련이 있습니다.
사실 'object 형식이 값 형식도 될 수 있고 참조 형식도 될 수 있는 이유'가 박싱과 언박싱이여서
object만을 위한 기능이기도 합니다. object 형식은 메서드랑 개념 정도만 다뤘었는데,
간단히 설명하면 모든 클래스, 구조체, 인터페이스, enum, 델리게이트의 부모입니다.
우리가 쓰는 모든 객체는 object 형식에 쓰인 메서드를 쓸 수 있습니다. 모든 클래스나 구조체 등의 부모라면,
동시에 모든 객체를 업캐스팅하여 object 형식의 변수에 담을 수 있고, 캐스팅을 통해
object 타입의 객체를 다른 모든 타입으로 바꿀 수 있을 것 입니다. (부모의 객체를 자식의 타입 변수가
참조하게 한다면 오류가 날 수 있지만 일단 컴파일 오류는 아니고 C#이 오류가 나지 않게
object 클래스를 잘 설계했습니다. 그리고 사실 구조체는 클래스나 구조체를 상속할 수 없지만
제가 거기까지는 자세히 공부하지 못해 일단 구조체는 구조체의 근본이 되는 클래스를 상속받는데,
그 클래스가 object 형식을 상속받는다는 것 까지만 설명하겠습니다.)
object a = 10; // 10이라는 값을 박싱해서 힙에 저장합니다.
int b = (int)a; // 10이 언박싱되어 b에 할당됩니다.
// a에 값에는 박싱된 10을 참조하는 '주소'가 들어있습니다.
// 즉 언박싱 없이 할당하면 값이 아닌 10을 향한 주소가 b에 할당됩니다.
- 문제점: 여기까지만 보면 문제가 없습니다. 그럼 object 형식을 사용해 보겠습니다.
C#에는 업캐스팅으로 자식 객체의 타입을 부모로 두고 사용할 수 있습니다.
그런데 위 코드처럼 int 형식의 객체를 업캐스팅해서 object 타입으로 사용하려고 할 때, int는 값 형식이죠?
그럼 10이라는 값은 스택에 있을까요? 전 객체 자체는 int, 즉 값 형식이기 때문에 원래대로
스택에 int가 차지하는 용량인 4byte만큼의 용량이 확보되고, 할당 될 것이라 생각했습니다.- 문제점 1. 용량 확보 불가능: 하지만 방금 한 '공간이 확보되고'라는 말이 문제가 됩니다.
C#에서 함수에 진입할 때, 미리 컴파일러가 코드를 읽고 int a; 처럼 변수가 선언되면
그 타입에 맞는 (int는 4byte) 공간을 미리 만들어주고, 컴파일이 끝난 코드 블럭의
처음부터 끝까지 하나씩 읽으며 공간을 할당, 측 채웁니다.
그런데 object 형식을 컴파일러가 읽었다고 합시다. 그런데 object 형식에는 1이 들어갈지,
0.0001f가 들어갈지, MyClass 객체가 들어갈지 컴파일러는 알 수 없기에 어쩔 수 없이
object 형식을 사용하면 컴파일러가 공간의 크기를 계속 바꿀 수 있는 힙 객체를 만들라는 명령을 내립니다.
쉽게는 컴파일러는 object 형식을 만났을 때 그 형식에 어떤 크기의 값이 들어갈지 모르기 때문에
힙이라고 판단합니다. 근데 int값을 힙에 넣어버리면 무슨 일이 생길까요? - 문제점 2. 값 타입 변수가 주소를 저장: object a = 10; int b = (int)a;를 했을 때
b는 힙에 있는 10이 아닌 a의 값에 해당하는 10을 가리키는 주소를
담게 됩니다. 부모와 자식 간에는 캐스팅이 가능하다는 규칙이 있기 때문에 이런 엄청난 버그를
해결할 방법이 필요했습니다. 그래서 만든 것이 박싱과 언박싱입니다.
10을 박싱(Boxing) 즉 포장해서 스택이 아닌 힙에 할당합니다. 그리고 값 형식이 이 10에 접근하면,
언박싱(Unboxing) 으로 포장을 풀고 주소가 아닌 10이라는 값을 꺼내 변수가 이 10에 접근하게 합니다.
그럼 값 형식의 변수는 엉뚱한 주소가 아닌 값을 저장할 수 있게 됩니다.
- 문제점 1. 용량 확보 불가능: 하지만 방금 한 '공간이 확보되고'라는 말이 문제가 됩니다.
Result: object는 모든 형식을 담아야 하므로 int, float와 같은 값 타입도 힙에 저장합니다. 하지만 힙에 저장하면 값 타입이 그 변수의 값을 할당하려고 할 때 주소가 할당되기 때문에 그 문제를 해결하기 위해 박싱하여 object는 값 타입을 힙에 저장할 때 박싱하여 힙에 값을 저장하고, 값 타입의 변수가 할당을 시도하면 언박싱하여 주소가 아닌, 값을 할당할 수 있게 합니다.
'공부 > C#' 카테고리의 다른 글
| [C#] 텍스트 파일 입출력 (File, FileStream, StreamWriter/Reader) (0) | 2025.12.02 |
|---|---|
| [C#] 죽음의 다이아몬드에 대한 개인적인 생각 (반박 환영) (0) | 2025.09.12 |
| [C#] Obscuring (0) | 2025.09.08 |
| [C#] Hiding (3) | 2025.09.07 |
| [C#] Shadoing (0) | 2025.09.06 |