call-by-reference, call-by-value + call-by-address
주소 | 0차 | 1차 |
&p | p | *p |
122EF560 | 125F7458 | 71 |
Note ) java에서 말하는 참조 변수와, C++에서 말하는 참조 변수가 다름을 알아야 혼동을 피할 수 있다.
C++에서 참조 변수는 java나 C에는 없는, 변수 자체의 alias 개념이다 ( case 3 참조 )
java에서 참조 변수란 C나 C++에서 말하는 포인터 변수와 동일하다. 즉 배열, 객체 등을 가리키는 변수를 말한다.
( C의 포인터 변수와 다른 점은 참조 변수에 아무 값이나 대입할 수는 없다는 것이다. )
아마 java가 포인터를 지원하지 않으면서 포인터 변수 보다는 참조 변수라는 말을 쓰는 것 같다.
case 1: call-by-value
java는 항상 call-by-value다. ( 정확하게는 call-by-sharing = call-by-object 라고 한다. python도 마찬가지. )
배열이나 객체를 넘길 때 주소가 넘어가니 call-by-reference라고 착각하기 쉽지만
"call-by-value where the value is reference" 라고 이해해야 한다.
참조 변수에 저장된 주소(p)가 넘어가게 되는데, 이는 type이 주소( reference )일 뿐 p라는 참조 변수에 저장된 value다.
그리고 받는 측에서 이것을 받아 p와는 다른 새로운 곳에 할당된 p0에 저장한다.
즉 변수에 저장할 "값"을 받았으므로, call-by-reference가 아니라 call-by-value다.
예제 코드는 차이를 알기 쉽게 모두 CPP pseudo-code로 작성했다.
```cpp
main(){
int *p;
swap(p);
}
swap(int *p0){
*p0 = 0;
}
```
case 2: call-by-address
그렇다면 포인터에 저장된 주소(a)자체가 변하면 call-by-reference인가?
포인터에 저장된 주소(a)를 변경하려면 포인터 변수 자체의 주소(&a)를 넘겨야 하니 call-by-reference인 것 같지만 변수 자체의 주소를 넘긴다고 해서 항상 call-by-reference인 것은 아니다.
C를 사용하다 보면 아래와 같이 포인터를 사용해 외부 함수의 변수에 접근하는 경우가 많은데,
C는 call-by-reference를 지원하지 않는다. 다만 포인터를 사용하면 call-by-reference처럼 쓸 수 있다.
```cpp
main(){
int a, b;
swap(&a, b);
}
/*call-by-reference, b는 call-by-value라고 착각하기 쉽지만
둘 다 call-by-value다.*/
swap(int *a0, int b0){
int tmp;
tmp = *a0;
*a0 = b0;
b0 = tmp;
//물론 b는 안바꿔진다만 예를 들기위해.
}
```
C에서는 이처럼 &a를 파라미터로 넘겨 a를 호출 func에서 수정할 수 있다.
&a로 a의 주소를 넘기므로 실제로 main함수의 a값이 변경되지만, 그렇다고 해서 이게 call-by-reference는 아니다.
a라는 변수 자체가 넘어간 것이 아니라 case1처럼 주소(&a)를 값으로 취급하고 이 값을 넘긴 것이며, a0이라는 변수에 담을 값을 받은 것이다. ( a0 = &a ) case1과 다른점은 변수 자체의 주소값이 넘어가긴 한다는 점이다.
변수 자체의 주소( &a )를 넘겨 함수에서 a를 수정할 수 있도록 하는 것. 이를 call-by-address라고 부르는 경우도 있다.
아무튼 swap이라는 함수 내에서 a의 값에 접근할 때는 * 연산자를 사용해서 포인터로 접근하는 수 밖에 없다.
call-by-reference는 다음과 같은 형식이다.
case 3: call-by-reference
a라는 변수 자체가 넘어가는 call-by-reference라면 위와 같이 받는 쪽에서 argument를 &a로 정의할 수 있어야 한다.
a1이라는 변수에 담을 값을 전달 받은게 아니라, a1자체를 a를 사용하는 것과 마찬가지로 사용할 수 있다.(alias)
C++에서는 이렇게 참조 변수, reference variable을 통해 call-by-reference가 가능하지만, C나 java 등에서는 이를 제공하지 않는다.
reference의 정확한 의미는 다음과 같다.
A reference is an alias, or an alternate name to an existing variable
즉 case3의 a1, b1은 reference variable이며 a, b의 alias다.
그러나 case2의 a0는 type부터가 포인터인, 단순히 a를 가리키는 새로운 pointer variable이다.
call-by-reference라면 *없이 사용 가능해야한다.
참고
https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_reference
'Coding Note' 카테고리의 다른 글
Encoding 정리. Unicode, ANSI, UTF, CP949 (2) | 2017.06.05 |
---|---|
IP parsing(+C), URL parsing 정규식 pattern (0) | 2017.02.01 |
서버 취약점 점검 체크리스트 (0) | 2017.01.27 |
객체 지향 5대 원칙 : SOLID (0) | 2016.09.13 |
객체 지향 패러다임 (0) | 2016.09.12 |