본문 바로가기
Software/C++&MFC 핵심노트

[C++/MFC 핵심노트] Function(함수) - call by value & call by reference

by lovey25 2019. 11. 6.

2021-04-15 update log: 기존에 사용한 예제가 C언어 스타일이라서, C++ 스타일의 예제 코드를 추가하였습니다.


함수에 Argument(아규먼트)를 전달하는 방법에는 2가지 가 있습니다. 값을 전달하는 방법과 참조를 전달하는 방법이 있는데요. 많은 곳에서 call by value, call by reference라는 이름으로 한번쯤 보신적이 있을 겁니다.

call by value와 call by reference 차이점

call by value라는건 아규먼트의 값을 그대로 함수의 파라미터의 복사를해서 사용하는 방법이고, call by referece는 아규먼트의 참조만 복사를 해서 함수의 파라미터로 사용하는 것을 말합니다.

저의 이해를 바탕으로 그림을 그려봤습니다.

call by value로 호출할때 전달되는 아규먼트는 원본인 데이터 "A"는 복사가 되어 새로운 "A"가 함수로 들어가게 됩니다. 그래서 함수안에서 파라미터에 어떤 변화, 여기서는 파라미터를 "B"로 수정을 했는데요, 수정을 한 파라미터는 복사된 새로운 데이터기 때문에 원본에는 아무런 영향을 미치지 못했습니다.

반면, call by reference로 호출하게 되면 함수에 어떤값이 복사되어 들어가는건 동일하지만 데이터값이 아니라 원본 데이터인 "A"가 저장된 주소값(#1)이 복사가 되어 전달이 된다는 점이 차이점입니다. 함수내부에서 파라미터를 "B"로 수정하는 동작을 수행할 때 전달된 주소값으로 데이터에 접근을 하기 때문에 #1주소의 아규먼트 자체가 변경이 되게됩니다. (call by reference와 call by address의 차이에 대해서는 무시하였습니다.)

call by Value 예시

// 예제 함수입니다.
void func(int x)
{
	x = 2;
}

void CMyFirstProgramDlg::OnBnClickedButton1()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	
	// ↓↓↓ << 실습용 코드가 시작되는 위치 입니다. >> ↓↓↓
	// ------------------------------------------------------

	int i = 1;
	func(i);
	myprint(i);
		
	// ------------------------------------------------------
	// ↑↑↑ << 실습용 코드가 끝나는 위치 입니다. >> ↑↑↑

	UpdateData(FALSE);
}

복사된 값이 파라미터로 전달되었기 때문에 원본은 변경되지 않아서 '1'이라는 결과가 나옵니다.

call by Reference 예시

C++ 스타일

void func(int& x)
{
	x = 2;
}

void CMyFirstProgramDlg::OnBnClickedButton1()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	
	// ↓↓↓ << 실습용 코드가 시작되는 위치 입니다. >> ↓↓↓
	// ------------------------------------------------------

	int i = 1;
	func(i);
	myprint(i);
		
	// ------------------------------------------------------
	// ↑↑↑ << 실습용 코드가 끝나는 위치 입니다. >> ↑↑↑

	UpdateData(FALSE);
}

C 스타일

void func(int *x)
{
	*x = 2;
}

void CMyFirstProgramDlg::OnBnClickedButton1()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	
	// ↓↓↓ << 실습용 코드가 시작되는 위치 입니다. >> ↓↓↓
	// ------------------------------------------------------

	int i = 1;
	func(&i);
	myprint(i);
		
	// ------------------------------------------------------
	// ↑↑↑ << 실습용 코드가 끝나는 위치 입니다. >> ↑↑↑

	UpdateData(FALSE);
}

두 코드모두 결과는 아래와 같이 동일합니다.

함수는 아규먼트의 값을 포인터로 원본을 수정하여 결과는 '2'가 되었습니다.

결론

함수 호출시 아규먼트의 전달방법 2가지를 비교해 봤습니다. call by value와 call by reference의 차이점을 다른말로 표현한다면, 함수가 외부의 변수에 영향을 줄 수 있느냐 없느냐의 차이라고 할 수 있습니다. 기능적인 차이점을 바탕으로 용도에 따라서 적절한 방법을 선택하여 사용을 하면 되는데요. 이때 고려해야 할 한가지 특징이 더 있습니다. 바로 함수의 수행속도 입니다.

구글링을 해 보면 call by reference의 속도적인 이점을 실험적으로 설명한 많은 글들을 쉽게 찾을 수 있습니다. 동작의 방식을 생각해보면 당연한 결과 입니다. call by reference는 원본 데이터의 크기에 관계없이 해당 데이터의 포인터만 아규먼트로 전달하기 때문에 실제로 복사되는 크기가 작아서 속도에 이점을 가지게 됩니다. 그리고 함수로 구성했다는 것 자체가 반복사용을 전재하고 있기 때문에 함수의 사용 빈도가 많아지면 많아질수록 그 차이는 더 커지게 되는것이죠.

그렇다고 무조건 call by reference를 쓰는게 좋은가하면 그렇지만은 않겠죠. 함수라는 것은 논리적 경계를 만듬으로써 코딩시 작업의 효율을 높이고자 하는데 그 목적이 있기 때문에 이런 특징을 고려하지 않고 남용되는 call by reference 는 오히려 프로그램에 치명적인 오류를 야기할 수 있다는 점을 유의해야 하겠습니다. 

 

끝!

728x90

댓글0