인프런 커뮤니티 질문&답변

움직이는YM님의 프로필 이미지
움직이는YM

작성한 질문수

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문

참조값 반환 질문

작성

·

136

0

Rookiss님 답변에서 궁금한 점이 생겼습니다.

은닉성 답변에서

void main()
{
   Knight k;
  int& hp = k.GetHp(); //< 일단 문제는 없음
}

이런 표현을 써주셨습니다.

제가 항상 헷갈리던게 반환형이 참조형이면 뭐가 반환되는가가 헷갈렸습니다.

예를 들어,

class Knight

{

public:

 

int _hp;

int& GetHp()

{

return _hp;

}

};

int main()

{

Knight k;

k._hp = 100;

int a = k.GetHp();

int& b = k.GetHp();

return0;

}

이런식으로 되어 있을 때

a와 b에서 일어나는 일의 차이를 잘 모르겠습니다

위 코드를 디스어셈블리로 살펴보면

int a = k.GetHp();

00A71939  lea         ecx,[k]  

00A7193C  call        Knight::GetHp (0A710B9h)  

00A71941  mov         eax,dword ptr [eax]  

00A71943  mov         dword ptr [a],eax  

int& b = k.GetHp();

00A71946  lea         ecx,[k]  

00A71949  call        Knight::GetHp (0A710B9h)  

00A7194E  mov         dword ptr [b],eax 

 ==> 이 실행문이 a에 하나 더 있는 걸 제외하고는 차이가 없습니다.

00A71941  mov         eax,dword ptr [eax]  

1. 참조값을 반환 한다는게 뭘 반환해 준다는 건가요?

- 예전 참조기초 강의에서

int* pointer = &number;

00BA2A59  lea         eax,[number]

00BA2A5C  mov         dword ptr [pointer],eax

*pointer = 2;

00BA2A5F  mov         eax,dword ptr [pointer]

00BA2A62  mov         dword ptr [eax],2

int& reference = number;

00BA2A68  lea         eax,[number]

00BA2A6B  mov         dword ptr [reference],eax

이 어셈블리를 통해 int*로 선언된 변수나 int&로 선언된 변수 모두 number의 주소를 담는 바구니라는 것을 확인했습니다.

위와 같은 사실로 제가 생각해 봤을 때,

-> 제 생각 :

반환형이 int& 라면-> 참조값 &, 포인터처럼 주소를 담는 바구니는 돌려준다

                        -> 그 바구니를 따라가다보면 나오는 데이터는 int형이다.

int a = k.GetHp()의 뜻 -> 바구니를 따라가다보면 나오는 int형 데이터를 복사해서 a라는 바구니에 대입해주겠다.

int& b = k.GetHp()의 뜻 -> 

00A7194E  mov         dword ptr [b],eax 
여기서 eax가 return시 [_hp의 주소]를 가지고 있다는 것을 확인했습니다.

(008550C9  call        Knight::GetHp (08510B9h)  를 F11로 들어가 확인해봤습니다)

즉 b는 _hp의 주소를 가지는 변수이다 -> 그런데 왜 메모리에서 &b를 찍으면 b의 주소에 _hp의 주소가 뜨는게 아니고 100이라는 값이 정확히 뜰까? -> C++에서는 참조라는게 그렇게 작동하니까

결국 리턴 값이 참조형으로 되어있으면 리턴되는 변수의 주소값이 넘어오는 것이다.

위와 같은 결론이 맞는 생각인지 궁금합니다.

답변 2

1

Rookiss님의 프로필 이미지
Rookiss
지식공유자

int a = k.GetHp()의 뜻 -> 바구니를 따라가다보면 나오는 int형 데이터를 복사해서 a라는 바구니에 대입해주겠다.

그게 맞습니다. 사실 눈으로 코드를 이해하려 하지 마시고
항상 메모리를 까보면 더 확실히 알 수 있습니다.


00A71941  mov         eax,dword ptr [eax]  
이 코드의 의미는 [eax 레지스터에 저장된 주소로 이동해서, 그 값을 다시 eax 레지스터에 저장]하는 것인데
원래 eax에는 _hp의 주소가 있고, 거길 이동해서 값을 꺼내서 eax에 저장하는 것입니다.
여기서 참조값은 해당 변수의 주소값을 이야기 하는것입니다.
이건 포인터나 참조나 별다른 차이가 없습니다.

두번째로 왜 &b를 하면 _hp의 주소가 뜨는게 아닐까?
~라는 질문을 하셨는데 매우 일리 있는 질문입니다.
C++ 관점에서 보면 참조란 결국 [원본을 건드리는] 형태로 동작하는 것입니다.
그리고 구체적으로 그것을 어셈블리로 변환했을 때 어떻게 만들지는 컴파일러 자유이고
C++ 관점을 훼손하지 않는 선에서 자유롭게,
최대한 빠르게 동작하는 코드를 만들 수 있습니다.
위의 경우에는 b라는 변수를 위한 공간을 따로 할당해서 주소를 넣기 보다는,
그냥 k._hp를 그대로 사용하는 쪽을 선택했고
그리하여 b는 사실상 C++에선 존재하지만,
어셈블리로 변환이 되면 '존재하지 않는' (k._hp랑 동일한) 아이로 인식되어
&b을 해도 우리가 예상한 주소 값이 들어있지 않은 것입니다.
참고로 이렇게 바로 사용하는 것으로 최적화가 가능한 이유는 
참조 특성상 값이 한 번 정해지면 더 이상 수정이 불가능하기 때문입니다.

0

자세한 답변 감사합니다!

움직이는YM님의 프로필 이미지
움직이는YM

작성한 질문수

질문하기