Call by Value 와 Call by Reference
Call by Value
1 | void change_value(int x, int val) { |
위 소스는 main에서 선언된 변수 x에 값 10을 주고 변수 x와 정수 val 매개변수로 하여 change_value를 호출한 후 change_value에서 x의 값을 val로 변경하는 소스이다.
실행을 하면 change_value에서 x의 값은 20으로 변경되었지만 main에서는 여전히 10이다.
이는 main에서 넘긴 x는 x의 값 10을 의미하기 때문에 이것을 바꾸어도 main의 x는 영향을 받지 않는다.
그래서 Call by Value이다.
Call by Reference
그렇다면 change_value에서 main의 x의 값을 어떻게 변경하는가?1
2
3
4
5
6
7
8
9
10
11
12#include <stdio.h
void change_value(int * x, int val) {
*x = val;
printf("x : %d in change_value \n", *x);
}
int main(void) {
int x = 10;
change_value(&x, 20);
printf("x : %d in main \n", x);
}
위 소스는 Call by Value와 거의 흡사하지만 결과는 다르다.
값이 변경되었다!
왜?!
main이 change_value를 호출 할 때 x의 값을 넘긴게 아니라 x의 주소를 넘겨 change_value에서 x의 주소의 값을 변경하여 main의 x의 값이 바뀌게 된다.
아닌데! 그거 Call by Address인데!
맞다. 사실 이것은 Call by Reference가 아니라 Call by Address라 부르는 그것이다.
주소를 넘겼는데 이 주소도 주소값
즉, 값이다.
그러니 Call by Value인데 주소를 넘겼기에 Call by Address라 부르는 것이다.
visual studio에서 change_value의 x값을 보면 위와 같다.
x에는 주소값이 들어있고 그 주소에는 20이 들어있다.
*x = val;
은 그 x의 주소에 들어있는 값을 val로 바꾸는 것이다.
그렇기에 x의 주소는 따로 존재한다.
즉 x라는 변수는 따로 메모리주소를 갖고 있으며 그 메모리 주소에는 값으로 주소를 가지고 있다. 그 가지고 있는 주소의 값은 main의 변수 x의 주소이기에 그 x의 주소를 가지고 값을 변경하는 것이다.
change_value에서 x가 가지고 있는 값은 main에서 x의 주소와 동일하다.
주소값
도 값
이기 때문에 Call by Value이고 주소
값이기 때문에 일반 값과 구분하여 Call by Address이다.
C에는 포인터만 있지만 C++에는 참조자가 있지!
이와 동일한 소스를 C++로 해보면 역시나 동일하다.
1 | #include<iostream |
하지만 이 소스를 참조자를 이용하여 짤 수 있다.
1 | #include<iostream |
위 change_value에서 x에는 정수 값이 들어있고 x의 주소는 main에서 x의 주소와 동일하다.
오오! c++에서 참조자를 이용한 함수 호출에서는 진정으로 Call by Reference가 이루어지는 것이다.
c에는 참조자가 없지? 아마?
그렇기에 Call by Address다.
어차피 컴파일러는 주소로 연산한다.
Call by Value, Call by Reference, Call by Address 다 값을 전달하는 건 똑같다.
Call by Reference는 호출 할 때 값을 전달하는 것처럼 보이지만 포인터로 받는거다.
다 똑같다. 어차피 컴파일러는 주소로 연산한다. 코드에서 선언을 포인터와 참조자 중 뭐로 했냐의 차이다.
C언어의 창시자인 데니스 리차드가 쓴 The C Programming Language를 보자.
C언어는 값
으로 인자를 전달한다.
Call by Reference는 호출 된 함수는 복사본이 아닌 원래 인수에 액세스 할 수 있는건데 결국 Call by Address도 주소값을 이용하여 원래 인수의 값을 바꾼다.
순서대로 Call by Value, Call by Address, Call by Reference다.
Call by Value는 call stack에서 호출된 함수는 호출을 한 main의 인자에 접근 할 수 없다.
나머지 둘은 접근한다.
함수가 자신의 stack frame의 인수에만 영향을 줄 수 있다면 Call by Value이고 자신을 호출한 stack frame에 인수를 변경 가능하다면 Call by Reference이기에 결국 주소를 이용하여 값을 변경하는 Call by Address도 값을 이용하지만 Call by Reference의 의미에 맞는게 아닌가 싶다.