[C++ 프로그래밍 / 이론] Chapter5. 스코프

YH·2023년 7월 26일
0

Chapter5. 스코프

변수 또는 함수 등의 이름이 통용되는 범위를 스코프라고 한다. 스코프는 지역 변수의 소멸 시점과도 관계가 깊다. 기본적으로 스코프는 중괄호 블럭을 통해 그 경계가 만들어지고 이를 블럭 스코프라고 한다. 블럭 스코프는 중첩될 수 있으며 블럭 스코프를 갖는 변수는 중첩된 모든 블럭 내에서도 통용된다.
중괄호 블럭 없이 정의되거나 선언된 이름은 전역 스코프를 갖는다. 전역 스코프를 갖는 이름은 모든 곳에서 언제든지 접근이 가능하다. 심지어 이들은 외부링킹이 적용되므로 다른 소스코드 파일에서도 extern 키워드를 통해 접근할 수 있다.

#include <iostream>

using namespace std;

struct Test //전역 스코프에서 정의
{
	Test(int num)
    {
    	cout << "test" << num << '\n';
    }
    ~Test()
    {
    	cout << "~test\n";
    }
};

int x = 10; //전역 스코프
int main()
{
	for(int i = 0; i < x; ++i)
    {
    	static int sCounter = 0; //전역 변수이지만 블럭 스코프를 가짐
        //int i; //심볼 중복 오류
        {
        	int i = 1; //상위 블럭의 i를 가림
            Test t(sCounter++); //Test 생성자 호출
            cout << ' ';
        } //t 소멸(Test 소멸자 호출)
        cout << endl;
    } //i 소멸
    int x = 10; //전역변수 x를 가림
    ::x = 20; //스코프 지정 연산자를 통해 가려진 전역 변수에 접근
}

블럭 스코프를 갖는 변수는 블럭 밖에서 접근이 불가능하기 때문에, 런타임에 제어흐름이 그 블럭을 벗어나는 순간 소멸한다. 이때 변수의 타입이 기본 내장 자료형이 아니라 클래스라면 소멸자가 자동으로 호출된다. 그러나 지역 변수가 블럭 스코프를 벗어나서 유효하지 않게 되더라도 스택의 크기는 함수가 끝날 때 까지 변하지 않기 때문에 함수 종료 시점까지 메모리를 점유하고 있다.
static으로 선언된 sCounter는 for문을 벗어나도 소멸하지 않는다. 이것은 전역 변수이며, 블럭 스코프를 갖는다. sCounter는 프로그램이 로드되는 순간 메모리를 점유하고 있고 선언 위치에서 생성 및 초기화된다. 이때 선언 위치가 반복문 안에 있더라도 생성 및 초기화는 처음 한 번만 수행된다.
같은 블럭 내에서는 심볼 중복이 허용되지 않는다. 중첩된 블럭에서는 허용되는데 컴파일러는 심볼을 찾을 때 가장 가까운 블럭부터 bottom-up 방식으로 탐색하기 때문에 상위 블럭의 같은 심볼은 가려지게 된다. 가려진 전역 변수는 스코프 지정 연산자를 통해 접근할 수 있다.

class A
{ //클래스 스코프
public:
	static int sCnt; //클래스 변수 선언(static 멤버 변수)
    int id; //멤버 변수
    A() : id(sCnt++) {}
    void updateId() //메서드
    {
    	//이 함수 내에서는 클래스 변수와 멤버 변수 모두 접근할 수 있음
        id = sCnt++;
    }
    static void resetCnt() //static 메서드는 static 멤버 변수만 접근 가능
    {
    	sCnt = 0;
    }
};
int A::sCnt = 0; //클래스 변수는 전역 스코프에서 정의해야 함

클래스 멤버 정의 중 static 키워드가 사용된다면 이는 클래스 변수를 만든다는 의미이다. 클래스 변수는 전역 변수이지만 클래스 스코프를 갖는 변수이다. 클래스 이름과 스코프지정 연산자를 통해 접근할 수 있고, 해당 클래스의 인스턴스가 있다면 인스턴스의 operator.을 통해 접근할 수도 있다. 메서드 내에서는 클래스 변수와 멤버 변수 모두 접근할 수 있으며, static 메서드에서는 클래스 변수에만 접근할 수 있다.


  • 무명 namespace

이 외에도 스코프의 경계를 만드는 도구로 namespace가 있다. 기본적으로 함수나 전역 변수는 외부 링킹이 적용되는데 특히 함수의 외부 링킹으로 인해, 서로 다른 개발자가 작성한 코드들이 심볼 중복으로 빌드를 못하게 되는 경우가 발생할 수 있기 때문에 namespace를 달리하여 구분하게 된다. 특히 함수나 전역변수를 내부링킹으로 바꾸는 방법의 일환으로 무명 namespace가 사용될 수 있다.

namespace { //무명 네임스페이스
	void f() { //같은 소스파일 내에서만 접근 가능
    	//구현 생략
    }
}
profile
Keep Recycling Your Dreams

0개의 댓글