7-1-나.지역변수의 장점

지역변수는 함수 내부에서만 사용할 수 있고 함수가 끝나면 파괴되는데 비해 전역변수는 모든 함수에서 자유롭게 사용할 수 있고 프로그램이 실행중인 동안은 계속 유지된다. 통용 범위도 넓고 지속 기간도 길기 때문에 모든 면에서 지역변수보다는 사용하기 편리하며 지역변수로 할 수 있는 거의 대부분의 일은 전역변수로도 할 수 있다.

그렇다면 지역변수라는 것은 아예 사용하지 말고 모든 변수를 전역으로 사용하면 될 것이다. 지역변수를 쓰지 않고도 얼마든지 프로그램을 작성할 수 있으며 실제로 지역변수를 지원하지 않는 언어도 있다. 어셈블리에서는 사실 변수라는 개념 자체가 없고 모든 것이 메모리 주소이기 때문에 모든 값은 전역이다(스택에 의도적으로 임시 변수를 생성할 수는 있다). 고전적인 베이직 언어에서도 지역변수라는 것이 없다. 하지만 C나 파스칼, 자바, 비주얼 베이직 같은 근대적인 언어들은 모두 지역변수의 개념을 지원한다.

심지어는 PHP나 ASP, 자바 스크립트 같은 스크립트 언어들까지도 지역변수를 지원한다. 왜 이런 언어들이 지역변수를 지원하는가 하면 프로그램의 구조화에 큰 도움을 주고 유지, 보수를 쉽게 해주는 등의 여러 가지 장점이 있기 때문이다. 지역변수가 전역변수에 비해 어떤 점이 우월하며 지역변수의 장점은 무엇인지 알아보자.

 

 함수의 독립성을 높인다. 프로그램은 함수로 구성되고 함수는 프로그램의 부품이라고 했다. 부품은 불가피한 경우를 제외하고는 가급적이면 스스로 작동할 수 있도록 만들어야 재활용하기 좋다. 부품끼리 공유하는 것(전역변수)이 많아지다 보면 의존 관계를 가지게 되므로 서로 얼키고 설켜서 좋지 않은 구조를 만들어 낸다. 부품은 전체를 구성하는 한 부분으로서 다른 부품과 상관없이 자신에게 부여된 임무를 독립적으로 수행할 수 있어야 한다. 다음 함수의 예를 보자.

 

int CalcSum(int bound)

{

     int i,sum;

 

     sum=0;

     for (i=1;i<=bound;i++) {

          sum+=i;

     }

     return sum;

}

 

이름만 봐도 무엇을 하는 함수인지 쉽게 짐작할 수 있을 것이며 본체의 코드를 보면 함수의 동작을 한눈에 파악할 수 있을 것이다. 이 함수는 인수로 전달된 bound까지의 총 합계를 구한다. 합계를 구하기 위해서는 루프 제어 변수와 누적값 저장을 위한 변수가 필요하며 CalcSum 함수는 i, sum 두 변수를 지역으로 선언해서 사용하고 있다.

만약 이 함수를 다른 프로젝트에서 사용하고 싶다고 해 보자. 똑같은 코드를 매 프로그램마다 다시 짤 수는 없으므로 함수를 재활용하는 일은 흔한 일이며 생산성 향상을 위해서도 함수를 적극적으로 재활용해야 한다. 이 경우 CalcSum 함수를 복사해서 붙여 넣고 함수 원형만 선언하면 바로 쓸 수 있다. CalcSum 함수 자체에 필요한 모든 변수들이 다 들어 있기 때문이다.

만약 이 함수가 사용하는 i, sum이 전역변수라고 해 보자. 그러면 함수를 가져 갈 때 전역변수들도 같이 가져가야 한다. 이 문제가 간단할 것 같지만 생각보다 복잡하다. 만약 새 프로젝트에서 i, sum 변수를 다른 목적으로 이미 사용하고 있다면 변수의 이름을 바꿔야 하고 함수의 본체에서 이 변수들을 참조하는 곳도 다 수정해야 하므로 재활용하기가 어려워진다.

재활용할 함수가 단독 함수라면 그래도 가져갈만 하겠지만 만약 일련의 함수군을 재활용하려면 어떻게 되겠는가? 이 함수군들이 사용하는 모든 전역변수 목록을 조사하고 이름이 충돌하는지 살펴보고 본체의 변수 참조문을 다 바꿔야 한다. 게다가 단순 변수도 아닌 구조체나 사용자 정의 타입이라면 재활용하는 것보다 차라리 다시 작성하는게 더 속편할 것이다.

지역변수는 함수가 자신이 필요로 하는 모든 정보를 다 가질 수 있도록(Self Contained) 해 줌으로써 함수의 독립성을 높여 준다. 그렇다면 이런 식으로 함수를 완전히 독립적으로 작성한다면 함수끼리의 정보 교환은 어떻게 하는가? 부품은 혼자 동작하는 게 아니므로 부품간의 정보 교환은 반드시 필요할 것인데 이럴 경우라도 전역변수는 사용할 필요가 없다. 왜냐하면 이럴 때 쓰라고 만들어 놓은 인수와 리턴값이라는 좋은 장치가 있기 때문이다. 함수끼리 정보를 주고 받기 위해서는 인수와 리턴값을 사용하는 것이 정석이다.

 지역변수는 디버깅 효율을 향상시킨다. 버그, 즉 논리적인 에러가 발생하는 원인의 십중팔구는 변수를 잘못 조작한 것이다. 전역변수가 편하다고 남발하다 보면 디버깅을 할 때 살펴 봐야 할 변수의 수가 많아진다. 프로그램 하나를 만들기 위해서 필요한 변수는 보통 수백개, 많으면 수천개가 되는데 이 변수들이 전부 다 전역이라면 디버깅은 정말 끔찍한 작업이 될 것이다. 더구나 전역변수는 통용 범위가 프로그램 전체이기 때문에 어떤 함수가 이 변수를 잘못 건드렸는지 찾아내기가 아주 어렵다.

그러나 지역변수는 디버깅하기 아주 쉽다. 일단 지역변수를 많이 쓰면 전역변수의 수가 상대적으로 줄어들게 되므로 관찰 대상 변수의 범위가 대폭 좁아진다. 또한 지역변수는 말썽을 부려봐야 자신이 소속된 함수안에서만 유효하므로 그야말로 뛰어봤자 벼룩이고 부처님 손바닥안의 손오공이다. 특정 지역변수가 말썽을 부린다면 그 함수 내부만 정밀하게 점검해 보면 금방 문제점을 발견할 수 있다.

프로그램이 대략 1000줄 정도만 되도 프로그램 개발 속도를 좌지우지하는 중요한 관건은 디버깅 속도이다. 프로그램 개발 기간에 소요되는 시간 중의 70%가 에러를 잡아내는 디버깅이라고 하지 않는가? 대형 프로젝트나 팀 프로젝트에서는 디버깅을 얼마나 빨리 할 수 있는가가 프로젝트의 성공을 결정한다. 디버깅의 간편함이 가지는 의미는 상상외로 크다.

 지역변수는 메모리를 절약한다. 전역변수는 프로그램이 실행될 때 같이 생성되며 계속 값을 유지해야 하므로 그만큼의 메모리를 항상 차지하게 된다. 지역변수는 함수가 호출될 때만 생성되며 함수가 종료되면 즉시 파괴되므로 자신이 속해 있는 함수가 실행중일 때만 메모리를 차지한다. 그래서 전역변수 대신 지역변수를 많이 쓰면 메모리를 절약할 수 있다.

 재귀 호출이나 상호 호출같은 특별한 기법은 지역변수가 있어야만 사용할 수 있다. 이런 기법에 대해서는 다음에 배우게 되겠지만 함수가 호출될 때마다 새로운 변수가 생성되어야만 가능한 기법이다. 재귀 호출이 가능하기 위해서는 각 호출시마다 고유의 값을 유지해야 하는데 전역변수로는 이런 기법을 구사할 수 없다.

 

지역변수가 전역변수에 비해 월등히 많은 장점을 가지고 있다. 전역변수는 편리하기는 하지만 복잡한 문제를 일으킬 수 있기 때문에 전역변수의 사용은 가급적이면 자재하는 것이 좋다. 전역변수를 전혀 사용하지 않고도 프로그램을 작성할 수 있다는 것이 이미 수학적으로 증명되어 있으며 전역변수를 병적으로 싫어하는 개발자들도 있다.

여러분들도 전역변수를 많이 썼다가 골치아픈 버그를 경험해 보면 왜 전역변수를 피해야 하는가를 실감할 수 있을 것이다. 가급적이면 지역변수를 사용하고 꼭 필요할 때만 전역변수를 쓰는 것이 좋다. 그렇다고 해서 또 전역변수를 너무 금기시할 필요까지는 없는데 적재적소에 제대로 사용한 전역변수는 프로그램의 논리를 간단하게 만들어 주기도 한다.