• 카테고리

    질문 & 답변
  • 세부 분야

    게임 프로그래밍

  • 해결 여부

    미해결

레퍼런스 질문드립니다

20.07.22 22:15 작성 조회수 150

1

제가 이해하고 있는 레퍼런스를 표현하기 위해

불가피하게  cpp 파일로 코드를 표현했습니다.

(유니티에서는 &(레퍼런스) 표현이 안 되더라구요)

#include <stdio.h>

void St(int& n)

{

printf("%x\n", &n);

        printf("%d\n", n);

}

int main()

{

int n = 10;

printf("%x\n", &n);

St(n);

return 0;

}

위 코드에서 레퍼런스 변수 n의 주소와 main함수의 

원본 변수 n의 주소가 같게 찍히더라구요.

그래서 레퍼런스는 그냥 원본 변수나 배열의 별명이라

생각했고, St함수에서 레퍼런스 변수 n을 출력하면

n이 값이  출력되기에 레퍼런스 n의 메모리 안에 원본 n의

값이 들어있다고 생각했습니다. 

그런데 오늘 설명해주신 레퍼런스 부분은

메모리를 따로 생성해 원본 변수 or 배열과 별도의 주소를 

가지고 메모리 안에 원본 메모리 시작주소 갖는

포인터의 개념 같아서요.  포인터는 *로

간접참조값 가져오던데

Player p= new Player();

에서 p가 * 나 & 같은 기호도 없고 레퍼런스라 생각하니 오히려

더 헷갈립니다. 

제가 생각했던 레퍼런스=별명이고

레퍼런스 변수 값(주소가 아니라)= 원본 변수 값 이라는

생각도 흔들려서 혼란스럽습니다. 

Player p= new Player(); 이 문장 해석을

그냥 타입사이즈 메모리로 객체 생성 하고 

객체 멤버변수를 default(0)으로 초기화 한다고 이해하고

넘어갈까요?

답변 2

·

답변을 작성해보세요.

0

그러고 보니 질문에 대한 대답을 안했네요 

Player p= new Player(); 

new Player()를 통해 생성자를 실행하면서 실제 메모리가 생겨나고 그 레퍼런스를 p에 대입합니다.

그리고 그냥 * 나 & 없이 그대로 사용합니다.

그래서 p변수(레퍼런스변수)가 실제 메모리를 참조한다 이렇게 이야기합니다.

0

안녕하세요. 제가 cpp 는 조금 공부만 해보고 안해봐서 답변을 드리긴 그렇습니다만

n의 주소를 그대로 함수에 넘겨주기때문에 같은 값이 아닐까 싶은 생각이 듭니다. cpp를 공부를 좀 해보고 나중에 이건 생각해볼 문제같고요. 

레퍼런스 문제는 C# 에서는 포인터가 없다고 생각하시면 됩니다.

윈도우즈에서 실행할때 unsafe 라는 형태로 포인터를 사용할 수는 있는데요.

무슨 일이 생길지 모르기 때문에 유니티에서는 사용을 안하시는게 좋을 것 같습니다. 

나중에 좀 고급문법에 나오는 ref 나 inout 같은 경우 포인터와 비슷하게 사용합니다만

그래도 포인터기호나 별표기호 같은 것을 사용하지는 않습니다. 

그래서 초보자들이 접근하기에 더 쉬운 면이 있습니다. 

C#에서는 레퍼런스는 기호 없이 그냥 사용합니다.

클래스로 만들어진 변수가 기호 없이도 그대로 접근해도

레퍼런스로 동작하고요.

값타입으로 되어 있는 변수들은 그대로 값으로 동작합니다.

다른 곳에서 보니 2중포인터로 내부적으로는 동작한다고 들었습니다만

그냥 1단 포인터변수의 동작과 동일하다고 생각하시고 별표나 & 연산자 없이 접근하시면 됩니다. (클래스의 경우에요)

레퍼런스 안에는 주소가 있고 실제 메모리가 다른곳에 존재합니다. 단 클래스만 그렇게 동작하고요.

구조체는 변수가 있으면 그대로 가보면 실제 메모리가 있습니다.

언어에 보통 만들어진 이유 같은것이 존재하는데요.

포인터가 초보자가 너무 어려워서 이걸 없애고 접근하려고 만든 것이 C# 언어라고 생각하고 있습니다. 

그래도 메모리의 주소는 보고 싶긴하죠 저도 그렇습니다.  그래서 C#에서는 주소는 볼수 없지만 해시코드는 볼수 있습니다. 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ManagerScript : MonoBehaviour
{
    public class ClassPos{
        public int x; public int y; public int z;
    }

    public struct StructPos
    {
        public int x; public int y; public int z;
    }

    public PlayerScript playerScript;
    void Start()
    {
        MyGameObject m = new MyGameObject();

        ClassPos c1 = new ClassPos();
        ClassPos c2 = c1;
        c1.x = 1;
        c2.x = 2;

        StructPos s1 = new StructPos();
        StructPos s2 = s1;
        s1.x = 10;
        s2.x = 20;

        print(c1.GetHashCode()); // 1
        print(c2.GetHashCode()); // 2
        print(c1.x.GetHashCode()); //3
        print(c2.x.GetHashCode()); //4

        print(s1.GetHashCode()); //5
        print(s2.GetHashCode()); //6
        print(s1.x.GetHashCode()); //7
        print(s2.x.GetHashCode());  //8


    }

}

이 코드 한번 실행해서 보시면 해시코드가 주소 비슷하게 보입니다. 

위에서 c2 = c1 을 실행했으므로 레퍼런스가 같은 메모리를 가르키고 있습니다.

1번 c1.getHashCode() ,  2번 c2.getHashCode() 같은 경우 클래스의 동작이므로 c1과 c2의 값이 c 언어 포인터같이 값이 같습니다.

3 4번의 경우도 값이 같습니다. 대입을 통해 레퍼런스가 같은 값이 되었으므로 같은 메모리를 참조 하기 있기 때문입니다.

5번 6번 같은 경우 구조체 같은 경우 값을 대입하고 있지만 다른 메모리에 생겨납니다. 구조체도 메모리이기 때문에 해시코드는 생겨납니다만 (내부적으로 주소는 있을 것입니다 하지만 저희가 사용하지 않습니다.) 구조체는 대입을 하면 서로 다른 메모리에 생겨납니다. 

7번8번 같은 경우에 위에서 각각의 x값에 10과 20을 대입했기 때문에 각각 다른 메모리가 있다는 것을 알수 있습니다.

그리고 다른 언어를 같이 적용하려고 하면 더 어려워 지는 것 같습니다. 새로 배운다고 생각하시고 접근하셔야 할 것 같습니다. 그래도 원래 지식이 있으니 도움은 크게 되겠죠.  cpp보다 C#이 훨씬 쉽습니다. 

감사합니다. 좋은 하루 되세요.