C++에서 Reference란 참조자라고 하여, 변수 자체가 아닌

변수를 가리키는 또다른 별명이라고 할 수 있다.

예를 들어 int형 변수 a가 있다고 할 때,

int &b = a 로 선언하고 b 값을 변경하면 실제 a의 값도 같이 바뀐다.


그래서 보통 swap 함수를 만들 때, 포인터로 넘겨주고 값을 변경하기도 귀찮고 하기 때문에 레퍼런스를 자주 사용한다.



1
2
3
4
5
void swap(int& a, int& b) {
    int tmp = a;
    a = b;
    b = tmp;
}
cs


처럼 말이다.

이렇게 변수로 함수의 인자를 받지 않고 레퍼런스로 받는 것을 Call-by-reference라고 한다.

(변수로 받는 것은 Call-by-value 라고 한다)


메모리를 공부했다면 여기서 어떻게 이게 되는지 신기할 수 있다.

포인터로 받아서 참조해서 값을 변경해준다고 하면 이해가 되겠지만, 레퍼런스로 받아서 값을 변조시키는 것은

그냥 봤을 때는 32비트 기준으로 EBP+8 주소의 값을 바꾸는 것과 같은 행동으로 보이기 때문에, 원본의 값과는 아무런 상관이 없어 보인다.

그래서 직접 디스어셈블링해서 구조를 확인해 봤다.




코드는 위와 같다.

간단하게 main에 a라는 int형 변수를 하나 선언하고 한번 출력한 다음,

이를 func에 Call-by-reference로 넘겨 값을 변경시킨 후 다시 출력하는 소스이다.



컴파일을 마치고 실행시켜 보면 의도했던 대로 a의 값이 변경되어 있는 것을 볼 수 있다.



그리고 gdb로 디스어셈블하여 내부를 살펴 보면, 나는 하지도 않았는데 자동으로 포인터 연산을 통해 값을 넣는 것이 보인다.

EBP+8에는 실제로 a의 주소가 들어 있었고, 이 주소를 참조하여 10을 넣어 준 것이다.

코드에서 내가 직접 짜주지는 않았지만, 컴파일러가 이렇게 되도록 컴파일한것이다.



이렇게 보고 나니 또 레퍼런스가 참조하는 변수를 바꿀 수는 없는가에 대한 생각이 들었다.

구글링해가면서 살펴보니 가능하기는 하더라.




이런식으로, functional을 include한 뒤, std::ref에 해당 변수를 넣어서 레퍼런스를 바꿔줄 수 있다.

저 std::ref같은 경우 'std::reference_wrapper' 타입을 리턴하기 때문에 쓰기 귀찮으니 auto를 쓰는게 편하다.

딱 봐도 레퍼런스를 변조하려고 하니 코드가 좀 복잡해졌다.

실제로 컴파일하고 실행시켜 보면,


(g++로 컴파일하려고 하니 -std=c++11 옵션을 줘야 하더라)


의도한 대로 값이 변경된 것을 알 수 있다.


이것도 로우레벨로 내려가서 좀 더 분석해보자.


(히익 이게 뭐야 무서워)


C++ 특성상 컴파일하고 나니 심볼이 엄청 더럽게 바뀌었다.

이래서 C++ 리버싱하는게 정말 싫은 것이다.


보아하니 EBP-0x20에 a 변수가 존재하고, EBP-0x24에 b 변수가 존재한다.

lea 명령으로 EBP-0x28의 주소를 edx에 넣고, EBP-0x20의 주소를 eax에 넣은 후,

push edx와 push eax를 수행한다.

이후 call하는걸 보니 std::ref의 첫 번째 인자로 &c, 두 번째 인자로 &a가 들어갔다.

이후 ostream이 나올 때까지 딱히 변화가 없는 것을 보아, 여기에서 c에는 이미 std::ref(a)가 들어갔음을 알 수 있다.

출력 이후, 맨 밑을 보면 c.get()이 실행되어 그곳에 포인터로 0xa를 넣는 것이 보인다.



아랫부분을 보니 또 이렇게 ebp-0x24 주소를 인자로 넘기고,

또 ebp-0x28 주소도 인자로 넘기는데, call을 여러번 수행한다.

아무래도 std::ref(b)를 수행한 뒤, 연산자 오버로딩 된 '='을 이용해 넣는 부분인 것 같다.

잘렸지만 이 부분 다음에 c.get()을 수행하고 0x14를 mov하는 부분도 있다.


결국 결론을 내리면 레퍼런스는 컴파일러딴에서 알아서 잘 포인터로 처리해 준다는 것.

우리는 그냥 실제 변수가 있는 것처럼 쓰기만 하면 된다.

블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요