변수 영역

컴퓨터 프로그래밍에서 변수 영역은 변수가 유효성을 갖는 영역을 가리킨다. 프로그램은 영역을 벗어난 변수를 가리킬 수 없다.

변수 영역을 지정하는 규칙은 크게 정적 영역 규칙과 동적 영역 규칙으로 나뉜다. 정적 영역 규칙을 따르는 언어에서는 변수의 유효 영역이 컴파일 타임에 결정되며, 동적 영역 규칙은 실행 시간에 결정된다. 대부분의 현대 언어는 정적 영역 규칙을 따르지만, 매크로를 컴파일할때는 동적 영역 규칙을 따르기도 한다.

종류

전역 

가장 간단한 변수 영역은 소스 코드 상의 모든 곳에서 사용할 수 있는 전역 변수이다. 전역 변수는 많은 언어에서 나쁜 관습으로 취급되지만, 그런 경우에도 함수명이나 클래스 명은 대부분 전역에서 접근할 수 있다. 이름공간을 사용하면 전역 영역에서 변수나 함수명이 충돌하는 것을 막을 수 있다.

모듈 영역 

모듈라나 파이썬과 같이 모듈을 지원하는 프로그래밍 언어에서는 모듈 단위 변수를 선언할 수 있다. 이 변수들은 같은 모듈 안에서만 접근할 수 있으며, 모듈 밖에서는 변수를 볼 수 없다.

C++ 등 모듈 개념을 지원하지 않는 일부 객체 지향 언어에서는 클래스가 모듈 영역의 역할을 대신하기도 한다. 모듈과 객체의 개념을 모두 지원하는 파이썬의 경우 모듈 단위 영역과 클래스 단위 영역을 둘 다 지원한다.

파일 영역 

파일 영역은 C와 C++ 및 그 유사 언어에서만 지원하는 개념이다. 이런 언어에서는, 소스 파일의 최상위에서 선언된 변수나 함수는 해당 파일 전체에서 접근할 수 있고, 다른 파일에서는 접근할 수 없다. 파일 영역은 보다 원시적인 형태의 모듈 영역으로 여겨진다.

함수 영역 

def square(n):
  return n * n

def sum_of_squares(n):
  total = 0
  i = 0
  while i <= n:
    total += square(i)
    i += 1
  return total

대부분의 프로그래밍 언어는 함수 내에서만 유효한 지역 변수를 제공한다. 함수 영역을 사용하는 지역 변수는 함수가 반환되면 더 이상 사용할 수 없다. 오른쪽의 파이썬 코드에서 변수 n은 함수의 인자로, 함수 밖에서는 사용할 수 없다. 또한 변수 total는 인자는 아니지만 함수 내에서 선언된 지역 변수로, 마찬가지로 함수 밖에서는 사용할 수 없다.

정적 영역 규칙에서는 함수가 다른 함수를 호출할 경우 변수는 영역 밖으로 벗어나게 되며, 해당 변수를 사용할 수 없게 된다. 그러나 동적 영역 규칙에서는 다른 함수가 호출되더라도 변수가 여전히 사용 가능하며, 함수가 최종적으로 종료될 때 비로소 변수가 영역 밖으로 벗어나게 된다. 동적 영역 규칙은 이런 특성으로 인해 소스 코드 단위에서 변수의 사용 가능 여부를 분석할 수 없고, 실행 시의 동작에 따라 변수의 사용 가능 여부가 바뀌게 된다. 이것은 종종 찾아내기 힘든 버그를 만들어낼 수 있기 때문에, 현대 프로그래밍 언어들은 대부분 정적 영역 규칙을 사용한다.

정적 영역 규칙의 경우, 함수 square의 인자 n과 함수 sum_of_squares의 인자 n은 이름은 같지만 서로 별개의 영역에 선언되어 있다. 따라서 두 변수는 완전히 독립되어 서로 어떤 영향도 끼치지 않는다.

만약 오른쪽 코드에서 동적 영역 규칙이 사용될 경우, sun_of_squares의 인자 n은 square의 인자 n과 겹치게 된다. 이 경우 이름 마스킹이 일어나, 기존의 n 변수를 가렸다가, 함수가 반환될 때 다시 원래 변수를 가리키게 될 것이다.

블록 영역 

unsigned int sum_of_squares(unsigned int n) {
  unsigned int ret = 0;
  for(unsigned int i = 0; i <= n; ++i) {
    unsigned int n_squared = i * i;
    ret += n_squared;
  }
  return ret;
}

알골과 그의 자손인 C, 그리고 그에 영향을 받은 많은 현대 언어들은 블록 단위 지역 변수를 지원한다.

예를 들어 오른쪽의 C 코드에서, 변수 i는 for 문 안에서만 유효한 루프 변수이다. 또한 n_squared는 블록 안에서 선언된 변수로, 블록 안에서만 유효하다. 한편 이 블록은 함수 안에 들어 있으므로, 블록 바깥에서 선언된 변수인 ret는 블록 안에서도 사용 가능하다. 블록 영역은 여러 개의 블록 안에서 선언된 변수들이 서로 간섭하지 않도록 하여, 에러의 가능성을 줄여 준다.

블록 영역 변수는 오른쪽 코드에서처럼 루프나 조건문에서 유용하게 사용할 수 있지만, 변수 영역을 제한하기 위한 용도로 블록을 따로 선언하는 것도 가능하다.

표현식 영역 

대부분의 함수형 프로그래밍 언어는 let 문을 지원한다. 예를 들어 ML에서 let val x = f() in x * x end 와 같은 표현식에서, 변수 x는 이 표현식 안에서만 유효하다. 이와 같은 표현식은 f()를 두번 호출하는 낭비를 막기 위해 쓰일 수 있다.

정적 영역 규칙 

정적 영역 규칙은 변수의 유효 영역이 소스 코드 상의 구조를 바탕으로 결정된다. 이로 인해 변수 영역은 실행 시간의 호출 스택이나 언어의 구현에 독립적이다. 이런 규칙에서는 변수의 유효 영역을 소스 코드만 보고 알아낼 수 있으므로, 문법적 영역 규칙(lexical scoping rule)이라고도 한다. 정적 영역 규칙은 알골과 그의 자손인 C, 그리고 대부분의 현대 프로그래밍 언어에서 사용된다. 이 규칙은 구조적 프로그래밍에서 변수의 수명 주기를 쉽게 알아볼 수 있게 하여 프로그램의 모듈성을 증가시킨다.

함수를 값으로 반환할 수 있는 함수형 프로그래밍 언어의 경우 정적 영역 규칙은 좀더 복잡하다. 함수를 선언할 당시 자신의 바깥 영역에 있는 변수를 사용할 수 있기 때문이다. 이 경우 내부에 중첩된 함수는 함수 코드와 함수 선언 시의 변수 환경을 같이 갖고 있게 되며, 이런 자료구조를 클로저라고 부른다.

동적 영역 규칙 

동적 영역 규칙을 사용하는 언어는 대개 호출 스택에 변수의 바인딩이 포함되어 있다. 변수가 선언될 때 스택의 맨 위에 각 변수가 선언되며, 프로그램의 흐름이 변수 영역을 빠져나갈 때 스택의 맨 위가 팝된다. 호출 스택은 런타임에만 동작하므로, 컴파일 타임에는 동적 영역 규칙을 실행할 수 없다.

동적 영역 규칙을 사용하는 언어로는 펄, 커먼 리스프 등이 있다. 또한 C 언어 전처리기를 비롯, 대부분의 언어에서 매크로의 변수 영역은 동적 영역 규칙과 유사한 규칙을 따른다.

프로그래밍 언어 개념