in 포스트

포인트와 참조 타입 차이

본래 집필중인 C# 책에 삽입하려고 했으나, 도저히 분량과 흐름상 삽입할 방도가 없어서 삭제한 글이다.

참조와 포인터 차이

지금까지는 쉬운 설명을 위해 참조 타입의 변수가 오브젝트를 가리킨다고 표현했습니다.

이것은 참조 타입의 변수가 오브젝트의 메모리 주소를 "직접" 가리킨다고 오해할 수 있는 표현입니다. 조금 정확하게 말하자면,

  • 변수가 오브젝트를 가리키는게 아니라, 변수에 할당된 참조값이 오브젝트를 가리키는 것입니다.
  • 참조 타입에 할당되는 참조 값은 메모리 주소가 아니라, 메모리 주소에 대응되는 값입니다. 메모리 주소를 직접 저장하는 것은 C# 참조 타입이 아니라 C++ 포인터 타입의 변수입니다.

컴퓨터의 메모리는 몇가지 영역으로 나뉩니다. 그 중에는 스택과 힙이 있습니다. 참조 변수에 할당된 참조는 스택 영역에 있고, 생성된 실제 오브젝트는 힙 영역에 있습니다.

다음과 같은 코드를 실행했다고 가정해 봅시다.

Animal a = new Animal();

우선, new를 통해 생성한 Animal 오브젝트가 힙 영역에 할당됩니다. 그리고 변수 a에는 Animal 오브젝트의 메모리 주소로 향하는 참조가 할당됩니다. a에 할당된 참조 값은 스택에 있습니다.

만약 생성된 Animal 오브젝트가 0x1200 메모리 주소에 할당되면, a에는 0x1200에 대응되는 참조값이 할당됩니다. 참조 값은 C# 프로그램을 구동하는 CLR 내부의 Index Table과 대응되는 해쉬 값입니다.

이때의 메모리의 상태는 다음과 같이 표현할 수 있습니다.

변수 aAnimal 오브젝트의 메모리 주소로 향하는 참조값을 저장하고, 참조값에 접근하면 CLR의 Index Table에서 참조값이 대응되는 메모리 주소로 이동하여 Animal 오브젝트에 접근합니다.

 

C#의 참조 타입과 비슷한 C++의 포인터 타입 변수는 메모리 주소를 직접 입력받습니다. 그런데 C++의 (unmanaged)포인터 타입에 할당된 값은 사칙 연산이 가능합니다. 따라서 실수로 할당된 주소값을 변형하고 프로그램을 망가뜨리기 쉽습니다.

C#의 참조 변수에 할당되는 값은 메모리 주소가 아니며, 사칙 연산이 금지되어 있기 때문에 메모리 주소 값을 직접 변형하여 프로그램을 망가뜨릴 염려를 하지 않아도 됩니다.

C++의 포인터 타입의 변수는 포인터 타입이 원래 가리키도록 의도된 타입이 아닌 오브젝트를 해당 변수에 강제로 우겨넣어 할당하는 것이 가능합니다.

하지만 C#의 CLR은 참조 변수가 대응하는 타입을 기억하기 때문에, 참조 변수에 대응되지 않은 타입의 오브젝트의 참조값을 할당하려하면 막습니다.

결론적으로 C#의 참조 타입은 메모리 주소를 랩핑한 값을 사용하므로 프로그램 작성 환경을 좀더 안전하게 만듭니다.

  • Related Content by Tag