7-1.지역변수

7-1-가.전역변수와 지역변수

기억 부류(Storage Class)란 변수가 저장되는 위치에 따라 결정되는 변수의 여러 가지 성질을 의미한다. 변수가 어디에 생성되는가에 따라 통용 범위와 파괴 시기 등의 특징이 결정된다. 이 내용은 C의 문법 체계를 이해하는데 상당히 중요한 비중을 차지하므로 숙독하여 완전히 이해하도록 하자. 기억 부류에는 4가지 종류가 있는데 일단 도표로 특성을 요약하였다.

 

기억 부류

전역

지역

정적

레지스터

지정자

extern

auto

static

register

저장 장소

정적 데이터 영역

스택

정적 데이터 영역

CPU 레지스터

선언 위치

함수의 외부

함수의 내부

함수의 내부

함수의 내부

통용 범위

프로그램 전체

함수의 내부

함수의 내부

함수의 내부

파괴 시기

프로그램 종료시

함수 종료시

프로그램 종료시

함수 종료시

초기값

0으로 초기화

초기화되지 않음

0으로 초기화

초기화되지 않음

 

이 도표의 내용을 당장 다 이해하기는 어렵겠지만 이 절을 모두 읽으면 이해가 갈 것이다. 일단 본문을 읽고 이해한 후 다시 이 도표를 보면서 기억 부류를 정리해 보기 바란다.

4가지 기억 부류 중에 가장 중요한 것은 전역변수와 지역변수를 구분하는 것이다. 이 두 부류는 성격이 판이하게 다르기 때문에 기억 부류의 모든 차이점을 살펴 볼 수 있다. 나머지 두 기억 부류는 전역, 지역 부류의 특성들을 조금씩 조합한 것이므로 이 둘만 확실하게 구분할 수 있으면 기억 부류는 다 아는 것이 된다. 다음 예제를 통해 두 기억 부류가 어떻게 다른지 비교해 보자.

 

: Storage

#include <Turboc.h>

void func();

 

int global;                    // 함수 외부에서 선언되었으므로 전역변수

 

void main()

{

     int local;                 // main 함수의 지역변수

    

     global=1;                // 가능

     local=2;                  // 가능

     i=3;                             // 불가능

}

 

void func()

{

     int i;                       // func 함수의 지역변수

 

     global=1;                // 가능

     local=2;                  // 불가능

     i=3;                             // 가능

}

 

 변수의 선언 위치가 다르다. 두 부류의 가장 뚜렷한 차이점인데 전역변수는 함수 바깥에서 선언하고 지역변수는 함수 내부에서 선언한다. 위 예제에서 global 변수는 main 함수 이전에 선언되었으므로 전역변수이고 local과 i는 각각 main 함수와 func 함수 내부에서 선언되었으므로 지역변수이다.

 변수의 통용 범위가 다르다. 통용 범위란 변수가 사용될 수 있는 범위를 지칭한다. 전역변수는 특정한 함수 내부에서 선언된 것이 아니므로 함수에 속하지 않고 프로그램 전체가 공유한다. 따라서 변수가 선언된 위치 이후에는 어디서든지 이 변수를 사용할 수 있다. 위 예제에서 보다시피 global은 main 함수나 func 함수에서 자유롭게 읽고 쓸 수 있다.

, 아무리 전역변수라 하더라도 자신이 선언된 이후에만 사용할 수 있다. 만약 위 예제에서 global 변수를 main 다음에 선언한다면 main에서는 global을 참조할 수 없다. 물론 func에서는 참조할 수 있다. C 컴파일러는 1패스 방식으로 동작하기 때문에 변수든 함수든 사용하기 전에 항상 선언을 먼저 해야 한다.

반면 지역변수는 자신이 선언된 함수에 소속되어 있기 때문에 함수 외부에서는 이 변수를 사용할 수 없다. 변수의 값을 읽지도, 쓰지도 못하며 변수의 존재 자체가 알려지지 않기 때문에 이 변수를 들먹거리는 것조차 허용되지 않는다. 지역변수는 함수가 자신의 임무를 수행하기 위해 잠시 쓰고 버리는 것이다.

main에서 자신의 지역변수 local에 값을 대입하거나 func 함수에서 자신의 지역변수 i를 사용하는 것은 가능하다. 그러나 main에서 i 를 참조하거나 func에서 local을 참조하는 것은 불가능하다. main 함수에게 i라는 변수는 없는 것과 마찬가지이다.

 변수의 파괴 시기가 다르다. 변수는 값을 기억하기 위해 메모리를 할당받아 사용한다. 변수를 다 사용했으면 파괴되는데 변수를 파괴한다는 것은 이 변수가 차지하고 있던 메모리를 회수한다는 뜻이다. 시스템의 메모리가 무한하지 않으므로 변수는 필요할 때만 메모리를 차지하며 다 사용하면 다른 변수를 위해 자리를 내 주어야 한다. 변수의 메모리가 회수되면 변수의 존재 자체가 사라진다.

전역변수는 프로그램에 소속되어 있고 모든 함수에서 사용 가능해야 하므로 프로그램이 실행중인 동안에는 파괴되지 않는다. 실행 직후에 생성되어 프로그램이 실행되는 동안에는 계속 메모리를 차지하고 있으며 프로그램이 종료되면 비로소 파괴된다. 즉, 전역변수는 프로그램과 운명을 같이 한다.

지역변수는 특정 함수 내부에서만 사용되므로 함수가 실행중일 때만 메모리를 차지하며 함수가 끝나면 변수의 생명도 끝이 난다. 함수의 임무를 위해 생성되는 임시 기억 장소이기 때문에 함수가 종료되면 더 이상 이 변수를 유지할 필요가 없어진다. 즉, 지역변수는 자신이 속해 있는 함수와 운명을 같이 한다. 함수가 호출되면 생성되고 함수가 끝나면 파괴된다. 그러다가 또 함수가 호출되면 생성되고 파괴되기를 계속 반복한다.

위 예제에서 global은 프로그램 종료시에 파괴되며 local은 main 함수 종료시에, i는 func 함수 종료시에 파괴된다. main의 지역변수는 우연히 전역변수와 생성, 파괴 시기가 거의 동일한데 이는 main 함수 자체가 프로그램 그 자체이기 때문이다.

 변수가 생성되는 기억 장소가 다르다. 전역변수는 한 번 정해진 메모리 위치에 계속 남아 있어야 하므로 정적 데이터 영역에 생성된다. 정적 데이터 영역이란 프로그램의 코드 바로 다음에 위치하는 실행 파일의 한 부분인데 프로그램이 실행될 때 메모리로 로드되어 실행중에 계속 유지된다. 지역변수는 프로그램 실행중에 생성, 파괴를 반복하므로 스택에 생성된다. 스택(Stack)이라는 용어는 조금 어려운 개념인데 일단 데이터의 임시 저장소라고 생각하기 바란다.

프로그램은 실행에 필요한 임시적인 정보들을 스택에 차곡차곡 저장한다. 지역변수, 인수, 함수 실행후 돌아갈 번지 등이 스택에 생성되었다가 사라졌다가를 반복한다. 지역변수는 임시 저장소인 스택에 생성되기 때문에 통용 범위가 함수로 국한되고 함수가 종료되면 같이 사라지는 것이다.

 초기화 여부가 다르다. 전역변수는 별도의 초기식이 없더라도 0으로 초기화된다. 위 예제의 global은 생성되자 마자 0이 될 것이다. 물론 int global=5; 와 같이 별도의 초기식을 주면 이 값으로 초기화된다. 전역변수는 컴파일될 때 컴파일러에 의해 초기화된 채로 실행 파일에 새겨지므로 초기화에 걸리는 시간은 0이다. 전역변수는 프로그램 전체에 걸쳐 사용되는 중요한 변수이므로 초기값을 지정하지 않더라도 안전을 위해 쓰레기값을 치워 0으로 초기화한다.

반면 지역변수는 별도의 초기식이 없을 경우 초기화되지 않는다. 따라서 무슨 값을 가지게 될 지 알 수 없는데 이때 초기화되지 않은 값을 쓰레기값(garbage)이라고 한다. 물론 선언할 때 초기값을 명시적으로 지정하면 초기화할 수도 있다. 초기값이 없을 때 지역변수를 초기화하지 않는 이유는 전역변수와는 달리 함수가 호출될 때마다 변수가 새로 생성되기 때문이다. 매번 변수를 초기화하자면 그만큼 실행 속도가 느려지므로 초기화를 하지 않는다.

지역변수는 함수 내부에서만 사용되므로 설사 지역변수의 쓰레기값이 문제가 된다 하더라도 그 함수만 점검하면 되지만 전역변수가 쓰레기값을 가지게 되면 프로그램 전체에 걸쳐 말썽을 부릴 수도 있다. 그래서 전역변수에 대해서는 초기값을 주지 않아도 쓰레기를 치우지만 지역변수는 그렇게 하지 않는다. 만약 지역변수에 쓰레기값이 들어가는 것이 싫다면 명시적으로 초기화를 해야 한다. 두 부류의 초기화 여부를 실험해 보기 위해 다음 예제를 실행해 보자.

 

: LocalGlobal

#include <Turboc.h>

 

int global;

 

void main()

{

     int local;

 

     printf("global is %d, local is %d\n",global, local);

}

 

전역변수 global과 지역변수 local을 선언하고 이 두 변수의 값을 출력해 보았다. 이 예제를 컴파일하면 local variable 'local' used without having been initialized 이런 경고 메시지가 출력된다. 번역하자면 "지역변수 local을 초기화하지 않고 사용했다"는 뜻인데 쓰레기값을 그냥 사용했으니 뭔가 이상하다는 뜻이다. 출력 결과는 다음과 같다.

 

global is 0, local is -858993460

 

global은 0으로 초기화되어 있지만 local에는 이상한 값이 들어 있다. 이 값은 실행할 때마다 달라지는데 지역변수가 생성된 스택 위치의 값이 그대로 출력되는 것이다. 스택에 어떤 값이 들어 있을지 예측할 수 없으므로 이 값을 쓰레기라고 하는 것이다.

 

보다시피 지역변수와 전역변수는 저장되는 장소가 다름으로 해서 상당히 많은 차이가 있다. 그렇다면 지역변수는 언제 사용하고 전역변수는 어떤 경우에 필요할까? 루프 제어 변수나 중간 계산에 필요한 변수와 같이 함수 내부에서 임시적인 용도로 쓴다면 지역변수를 사용하고 프로그램 전체에 걸쳐 값을 유지해야 하는 변수는 전역변수를 사용한다.