본문 바로가기

# Lang/C++

3.2 기억영역 클래스 지정자

 기억영역 클래스 지정자  (Storage Class Specifiers)

스토리지 클래스는 변수의 다양한 특성을 결정하며,

C++에서 지원하는 스토리지 클래스는 다음과 같다.



스토리지 클래스가 결정하는 변수의 특성 :

  • 변수의 범위 
  • 생명주기
  • 링크특성  
    1. 외부링크   :  외부소스의 변수를 참조.
    2. 내부링크   :  내부소스의 변수를 참조.



C++ 기억공간 클래스 :

  • auto   (untill C++11,  키워드의 의미가 변경됨)
  • register    (untill C++11, 폐기됨)
  • static
  • extern
  • thread_local   (since C++11)
  • mutable





 Auto 스토리지

  • C++11 이전

일반적으로 사용되는 변수의 스토리지 타입이다.

스택에 쌓이며, 범위를 벗어나면 스택에서 제거되어 사라진다.

변수의 생명주기가 자동적으로 관리된다는 뜻에서 자동변수라는 이름이 붙었다.


/* C++ 11 이전 */
auto int a = 3;    // OK, auto는 기억공간 지정자이다.



  • C++11 이후

리터럴의 자료형을 분석하여,  변수의 자료형을 추론하는 기능이 추가되었고.  (auto data type,  Since C++11)

auto의 역할이 위의 기능으로 대체되었으며,  스토리지 지정자의 기능을 잃었다.


/* C++ 11 이후 */
auto int a = 3;  // ERROR,  auto는 더 이상 기억공간 지정자가 아니다.
auto b = 3;  // OK, auto는 리터럴의 자료형을 추론한다.  int b = 3; 과 같다.


기능이 변경된 것 뿐이지, 그 특성은 여전히 쓰이고 있다.

지금도 명시자를 지정하지 않으면, 자동변수으로 취급한다.





 Register 스토리지

  • C++11 이전

변수를 RAM이 아니라,  가능한 Register에 저장하도록 요청한다.

레지스터에 여유가 없으면 이 요청은 무시될 수 있다.


컴퓨터에 얼마없는 레지스터를 사용하기 때문에, 전역변수에는 사용할 수 없고.

레지스터에 저장되기 때문에 주소값을 가져올 수 없다.


레지스터 변수에 주소값 취득을 허용하는 컴파일러는,

내부적으로 레지스터 요청을 무시하고, RAM에 저장시켜 주소를 갖도록 한다.



  • C++17 이전 

변수를 레지스터 스토리지로 선언하면 Warning을 발생시키거나,

일부 컴파일러는 요청을 무시하고 RAM에 저장한다.



  • C++17 이후

변수를 레지스터 스토리지로 선언하면 Compile Error를 발생시킨다.





 static 스토리지

변수가 내부링크의 속성으로 선언되도록 한다.



내부링크의 속성 :

  • 같은 소스코드 파일 안에서 같은 이름을 갖는 모든 변수는 하나의 메모리만 사용.

  • 처음으로 선언문을 만났을 때만 선언식을 수행하고, 이후에는 무시한다.


int set_and_get(int v){
    static int s_int = v;   // 초기화는 변수 생성시, 단 한번만 발생한다.
    return s_int;
}


int main() {
    cout << set_and_get(0) << endl;   // print 0
    cout << set_and_get(1) << endl;   // print 0
    cout << set_and_get(2) << endl;   // print 0

    return 0;
}


여러번 함수를 호출하여 s_int의 값을 바꾸려고 했지만,

2행의 초기화는 한번만 발생하고 무시되므로, 첫 값인 0에서 바뀌지 않는다.


올바르게 바꾸면 다음과 같다.

int set_and_get(int v){
    static int s_int = 0;   // 초기화는 변수 생성시, 단 한번만 발생한다.
    s_int = v; 
    return s_int;
}


int main() {
    cout << set_and_get(0) << endl;  // print 0
    cout << set_and_get(1) << endl;  // print 1
    cout << set_and_get(2) << endl;  // print 2

    return 0;
}





 extern 스토리지 

변수가 외부링크의 속성으로 선언되도록 한다.



외부링크의 속성 :

  • 다른 소스코드의 변수를 가져올 수 있음.
  • 단, 내부링크(static) 변수는 가져올 수 없음.

/* data.cpp */
int e_i = 1;
static int s_i = 2;
const int c_i = 3;

/* main1.cpp */

int main(){
    extern int e_i;
    cout << e_i << endl;   // print 1;
}
/* main2.cpp */

int main(){
    extern int e_i;
    extern int c_i;
    cout << s_i << endl;   // Link Error,  내부링크 변수를 외부링크로 가져올 수 없음.
    cout << c_i << endl;   // Link Error,  const도 내부링크 속성.
}





 Thread_Local 스토리지 (Since C++11)

전역으로 선언될지라도,  각 쓰레드마다 별도의 변수로 적용된다.

extern과 static을 추가적으로 조합하여 링킹할 수 있다.


int v = 0;  // 모든 쓰레드가 하나의 v를 사용.
void ThreadFunc(int nID)
{
    v++;
    cout << nID << "th Thread : " << v << endl;
}


int main()
{
    for(int i=0; i<5; i++)
    {
        thread th(ThreadFunc, i);
        th.join();
    }

    // 0th Thread : 1
    // 1th Thread : 2
    // 2th Thread : 3
    // 3th Thread : 4
    // 4th Thread : 5
}
thread_local int v = 0;  // 각각의 쓰레드가 v를 생성하여 사용.
...

    // 0th Thread : 1
    // 1th Thread : 1
    // 2th Thread : 1
    // 3th Thread : 1
    // 4th Thread : 1





 Mutable 스토리지

클래스 멤버 변수에만 적용할 수 있으며,  멤버 함수의 const 제약을 무시한다.

링크와 아무런 관련없는 스토리지 타입.


또 다른 의미로는, 

람다함수의 캡쳐시, 파라미터의 const 제약을 제거하는 것 이다.


class Box{
public:
    mutable int data = 0;
    void save(int _data) const
    {
        data = _data; // 멤버함수에 const 제약이 있지만 뚫는다.
    }
};





 스토리지 스펙 정리





 참고문헌

https://en.cppreference.com/w/cpp/language/storage_duration

 

Storage class specifiers - cppreference.com

The storage class specifiers are a part of the decl-specifier-seq of a name's declaration syntax. Together with the scope of the name, they control two independent properties of the name: its storage duration and its linkage. auto - automatic storage durat

en.cppreference.com

https://psychoria.tistory.com/241

 

[C++11] Storage class specifiers에 thread_local 추가

Storage class specifiers는 기존에 register, static, extern, auto가 존재했습니다. auto는 의미가 없기 때문에 C++11에서는 다른 용도로 사용됩니다. 2014/12/10 - [Programming/C++11&14] - [C++11] auto 키워..

psychoria.tistory.com

 

'# Lang > C++' 카테고리의 다른 글

4.2 값의 유형 (glvalue, prvalue, xvalue)  (0) 2019.04.11
4.1 표현식  (0) 2019.04.10
3.1 CV 제한자 (const, volatile)  (0) 2019.03.31
2.3 자료형과 형변환  (0) 2019.03.29
2.2 자료형과 데이터 해석  (0) 2019.03.27