03
13

생각보다 강한 구조체...

C언어의 사용자 정의 자료형에는 구조체 struct, 공용체 union, 열겨형 enum이 있지만

 

C#에선 셋중 공용체가 없어서 구조체 struct와 열거형 enum만 있다.

 

물론 공용체를  쓰고 싶으면 아래의 글에서 편법으로 쓸 수 있다고 한다. ↓

C#에서 Union 구현하기

 

오늘은 구조체만 한번 다뤄보자

 


#1 구조체 struct

 

구조체란 하나 이상의 변수들을 묶어서 그룹으로 만드는 사용자 정의 자료형이다.

 

사용 목적 자체는 변수들을 그룹화하고 값형식이라 값으로써 사용하기 위한거다.

 

게임을 만들 때 플레이어의 스탯을 그룹으로 만든다면 참조하여 쓰기 편리하다.

 

이제 구조체를 정의해볼건데 구조체 정의한다는건 구조체 이름, 구조체 멤버 변수를 만든다는 뜻이다.

//* 접근제한자 struct 구조체 이름
public struct Player
{
    public int Health {get; set;} //* 프로퍼티 get set
    public float Mana; //* 멤버 변수
    public void Dead() //* 멤버 메서드(함수)
    {
        if(Health <= 0)
        {
            bool isDead = true;
        }
    }
}

접근제한자 뒤에 struct 키워드를 쓰고 구조체 이름을 쓰면 된다.

 

구조체 안에는 생성자, 프로퍼티, 멤버 변수, 멤버 메서드(함수), 이벤트가 올 수 있다.

 

이렇게 정의한 구조체의 사용 방법은 간단하다.

 

private void Start()
{
    Player player;
    player.Health = 0;
    player.Mana = 0;
    player.Dead();
}

 

클래스 내에 함수에서 구조체를 선언해서 사용하면 되는데 실제로 위에처럼 하면 에러가 뜰 것이다.

 

이유는 Dead()와 Health가 각각 메서드(함수)와 프로퍼티인데 이것들이 할당을 안했다고 에러가 계속 뜬다.

 

이럴 때 구조체 고유의 인스턴스를 만들고 다시 할당하면 된다. 즉 재할당을 해주면 된다.

 

private void Start()
{
    Player player;
    player = new Player(); //인스턴스 생성
    player.Health = 0;
    player.Mana = 0;
    player.Dead();
}

이런식으로 하면 된다.

 

위에서 메서드와 프로퍼티만 에러 뜬다고 했는데 값형식 다 인스턴스 생성해 재할당 해줘야한다.

 

멤버 변수는 변수가 참조타입(클래스)같은거만 아니라면 꼭 재할당 안해도 되는거같다.

 

근데 Player player을 Start함수가 아닌 더 위에서 선언하면 에러가 안뜨던데 왜그런진 모르겠다.

 

그리고 위에서 말한거처럼 구조체안에는 이벤트도 올 수 있다.

//* 접근제한자 struct 구조체 이름
public struct Player
{
    public int Health {get; set;} //* 프로퍼티 get set
    public float Mana; //* 멤버 변수
    public void Dead() //* 멤버 메서드(함수)
    {
        if(Health <= 0)
        {
            bool isDead = true;
        }
    }
    public event EventHandler OnEvent; //* 이벤트 핸들러

    public void InvokeEvent() //* 이벤트 실행을 위한 멤버 메서드(함수)
    {
        if (OnEvent != null)
        {
            OnEvent(this, EventArgs.Empty);
        }
    }
}
void Start()
{
    Player player = new Player(); //* 인스턴스 생성
    customEventStruct.OnEvent += CustomEventHandler; //* 이벤트 구독

    customEventStruct.InvokeEvent(); //* 이벤트 실행 메서드 호출
}

구조체안의 이벤트는 어디다  써야할지 감이 안온다.

 

아무튼 구조체상속이 불가능한데 Interface 구현은 가능하다.

 

그럼에도 구조체를 사용하는 이유는 위에서 말한 것처럼

 

일반적으로 클래스보다 가볍고 속도가 빠르고 데이터를 저장하고 전달하는데 효과적이기 때문이다.

 

그 이유는 아래 사진에서 스택 부분에 저장되기 때문이다.

 

 

구조체는 값 형식이기 때문에 스택 영역에 저장되어 메모리 할당과 해제가 간단하고 빠르다.

 

또한 구조체는 스택 메모리에 저장되므로 클래스와는 달리

 

힙 메모리를 사용하지 않아 가비지 컬렉션 부하가 발생하지 않는다.

 

근데 이게 오히려 독이 될 수도 있는데

 

구조체의 크기가 너무 커지거나 구조체 인스턴스를 불필요하게 많이 생성하면 

 

스택 메모리가 과도하게 사용될 수 있는데 그러면 스택 오버플로 발생할 수 있다.

 

그냥 적당하게 상황에 따라서 최대한 적게 쓰면 될듯하다.

 

 

위에서 구조체값 형식이라고 했는데 그러면 클래스는 무슨 형식일까?

 

클래스참조형식으로써 데이터의 실제 값이 메모리 공간을 가지지 않는다.

 

참조 형식의 인스턴스(클래스)는 힙 메모리에 저장된 데이터를 참조만한다.

 

때문에 메모리 할당과 해제가 복잡하고 가비지 컬렉션에 의해 메모리 관리가 이루어진다.

 

그리고 구조체와 다르게 상속, 다형성 등을 지원한다.

 

아무튼 구조체를 알아보는 김에 클래스도 다시 알게 된 것 같다.

 

구조체도 상황에 따라서 유연하게 쓰도록 하자

 


#2 구조체 struct 배웠으니까 활용법도

 

이제 유니티에서 구조체를 사용할만한 예시를 몇가지 보자

 

1. 색 구조체

우선 색 구조체 하나를 만들어보자 ↓

public struct Color {
    public float r, g, b, a;

    public Color(float r, float g, float b, float a) {
        this.r = r;
        this.g = g;
        this.b = b;
        this.a = a;
    }
}

그 다음 나만의 색을 저장할 구조체를 선언하자 ↓

Color red = new Color(1, 0, 0, 1);
Color green = new Color(0, 1, 0, 1);

 

위에서 구조체를 설명할 때 값 형식이라고 했기 때문에 이런식으로 값 저장식으로 활용하면 좋다.

 

개인적으로 저렇게 저장해둔 컬러 값처럼 카메라 필터 값을 저장해 필요한 상황에 쓰는것도 좋겠다고 생각함 

 

2. 캐릭터 스탯 구조체

struct CharacterAttributes 
{
    int health;
    int attackPower;
    int defensePower;
}

CharacterAttributes myCharacterAttributes = new CharacterAttributes();
myCharacterAttributes.health = 100;
myCharacterAttributes.attackPower = 50;
myCharacterAttributes.defensePower = 20;

일반적으로 캐릭터 스탯을 이렇게 저장하는듯하다.

 

번외) ChatGPT가 알려준 애니메이션  정보 저장 구조체

struct AnimationInfo 
{
    string animationName;
    float speed;
    bool loop;
}

AnimationInfo myAnimationInfo = new AnimationInfo();
myAnimationInfo.animationName = "Run";
myAnimationInfo.speed = 1.5f;
myAnimationInfo.loop = true;

이렇게 말고도 활용할 부분은 굉장히 많을듯하다.

 

구조체..생각보다 강한거같다

COMMENT