본문 바로가기

취미로 하는 게임코딩_gameCodingAsHobby/유니티unity로 게임 만들기

유니티25_C#15_구조체(Struct)

구조체 (Structure , Struct)

 

Struct(구조체)는 Class(클래스)와 함께 객체를 생성하는 기본적인 두가지 틀 중의 하나이다.

구조체 또는 클래스를 정의하면 구조체명 또는 클래스명이 타입(type)명이 된다.

이 타입으로 인스턴스(객체)를 만들 수 있다.

 

구조체와 클래스의 가장 두드러진 차이점은 다음과 같다.

 

  • 클래스는 참조 타입(reference type)이다.
  • 구조체는 값 타입(value type)이다.

참조 타입은 객체가 저장된 변수에 메모리의 참조(저장되어 있는 주소)만 가지는 구조이다.

값 타입은 메모리에 실제 데이터를 저장하는 구조이다.

 

구조체에서는 일반적으로 struct가 만들어지면 그 이후에 변경되지 않는 데이터를 가지는 소규모 데이터 구조를 만들 때 사용한다.

 

구조체 만드는 법과 특징은 다음과 같다.

 

  • 구조체 정의는 struct 키워드를 사용한다.
  • 구조체 필드는 초기화할 수 없다.
  • 구조체 생성자모든 필드인수(매개변수)로 받아서 값을 할당해야 한다.
  • 구조체 안에 인터페이스를 구현할 수 있다.
  • 구조체는 상속할 수 없다.

 

구조체의 예는 다음과 같다.

비주얼스튜디오 코드를 실행한 후 StructExample.cs 스크립트 파일을 만든다.

 

11번줄에서 Coordinates(좌표)라는 구조체를 선언한다.

13,14번줄에 구조체 필드 x , y를 선언하고 초기화는 하지 않는다.

16번줄에 모든 필드를 매개변수로 하는 생성자를 만든다.

18,19번줄에 구조체 필드 x에 인수로 받은 x값을 저장하고, 필드 y에 y값을 저장한다.

22번줄에 string(문자열) 타입의 GetPoints메서드를 만든다.

24번줄에 필드 x,y값을 문자열 (x, y) 형태로 반환한다.

 

만든 구조체로 인스턴스(객체)를 생성하여 값을 출력 해보자.

 

 

7번줄에 Coordinates 타입의 twoPoints(두 점)라는 변수에 저장한다(=).

(무엇을?) new키워드를 사용하여 인수(1,2)를 전달하는 구조체의 인스턴스(객체)를.

 

8번줄에 twoPoints의 GetPoints메서드로 반환 받은 문자열을 출력한다.

 

유니티에서 실행하면 다음과 같은 결과가 나타난다.

 

 

Value Type과 Reference Type

 

 

만약 otherPoints라는 변수에 twoPoints 변수를 저장하면 그 값이 복사되어 저장된다.

두 변수에 저장된 값을 출력하면 다음과 같다.

 

 

 

그런데 otherPoints의 x , y 값을 다른 수로 바꾸어 저장한 후 두 변수를 출력하면 다음과 같다.

 

 

제일 위에서 구조체는 Value Type(값 타입)이고 클래스는 Reference Type(참조 타입)이라고 했다.

어떻게 차이가 나는지 알아본다. 

 

처음에 twoPoints에 들어있는 값을 otherPoints에 넣으면 그 값이 복사되어 저장된다.

그 상태에서 otherPoints 값을 다른 값으로 바꾸어 저장하면 당연히 바꾼 값이 저장될 것이다.

그리고 twoPoints값도 처음에 저장되었던 값을 그대로 유지한다.

이것이 Value Type(값 타입)의 특징이다.

 

이제 reference type인 클래스는 어떻게 작동하는 지 알아보기 위해 아래와 같이 struct를 class로 수정한다.

 

스크립트 파일을 저장한 후 유니티에서 다시 실행하면 다음과 같은 결과가 나온다.

 

 

결과와 같이 otherPoints값을 수정하면 twoPoints값도 함께 수정되었다.

이것이 Reference Type(참조 타입)의 특징이다.

 

Stack(스택)메모리와 Heap(힙)메모리

구조체와 같은 Value Type 에서는 new키워드로 인스턴스(객체)를 생성하면 '스택'이라는 메모리에 저장한다.

만약 '스택'에 저장되어 있는 값을 다른 곳에 저장하면 복사해서 '새 스택' 메모리에 저장한다.

즉, 처음 스택에 있던 값과 복사한 새 스택의 값은 내용만 같고 별개의 메모리 공간을 차지하여 저장되어 있다.

 

그런데 클래스와 같은 Reference Type 에서는 new키워드로 인스턴스(객체)를 생성하면 일단 '힙'이라는 메모리에 저장한다. 그리고 어떤 변수A를 선언하면 '스택' 메모리에 공간을 마련한다.

 

만약 Reference Type의 객체를 이 변수A에 저장하면 해당 객체가 저장되어 있는 힙 메모리의 주소(address)만 저장된다. 즉, 인스턴스(객체)를 저장하는 것이 아니라 어디에 있는 지 위치만 기억하게 된다.

 

이 상태에서 변수A가 다른 변수B에 저장되면 변수B를 위한 새 스택 메모리가 만들어지지만 그곳에 저장되는 객체는 변수A와 마찬가지로 객체의 주소(위치)만 저장된다.

 

그래서 변수B의 값을 변경하면 객체의 주소로 찾아가서 그 힙 메모리에 저장된 값을 수정하게 된다.

그러므로 변수A 역시 객체가 있는 주소로 가면 수정된 값을 확인하게 될 것이다.

 

결론적으로 일반적인 저장은 'Stack'메모리가 담당하고 Reference Type(참조 타입)을 위해서는 별도의 'Heap'메모리를 사용한다.

 

추가로 Value Type인 구조체는 객체든, 변수든 모두 '스택' 메모리에 저장하므로 아래와 같이 변수 선언만 해도 인스턴스(객체)가 생성되어 저장되므로 구조체의 멤버에 접근할 수 있다.

 

 

7번줄에 구조체 Coordinates 타입의 변수 twoPoints를 선언한다.

9,10번줄에서 이 구조체 변수로 필드 x , y 에 접근해서 값을 저장한다.

 

출력하면 다음과 같이 확인할 수 있다.

 

 

하지만 클래스는 new키워드로 인스턴스(객체)를 생성해서 힙 메모리에 저장하는 참조 타입이므로 변수만 선언하면 힙 메모리에 참조할 주소가 없기 때문에 다음과 같은 컴파일 오류가 나타난다.

 

에러 해석 : 할당되지 않은 지역 변수 'twoPoints'를 사용하고 있다.

 

이전 글에서 보았던 모든 데이터 Type(타입)은 Value type(값 타입)과 Reference type(참조 타입)으로 나눌 수 있다.

 

Value type의 예는 다음과 같다.

 

  • 정수 타입( byte, short, int, long 등 ) 
  • 실수 타입( float , double )
  • 문자 타입( char )
  • 논리 타입( bool )
  • struct
  • enum

 

Reference type의 예는 다음과 같다.

 

  • 문자열 ( string )
  • 배열 ( arrays )
  • object
  • class
  • interface
  • delegate

끝.

Wraven...