static

정적. 무언가를 데이터 영역에 할당해서 라이프타임을 프로그램의 시작과 끝으로 하기 위해 붙이는 키워드

반대되는 개념으론 dynamic한 무언가. 예 : 정적배열<-> 동적배열

그런데 어디서 선언되냐에 따라서, 즉 선언된 스코프에 따라서 의미가 조금 다르다.


1. 일반 함수 내의 지역변수로 선언될 경우

함수내의 static 변수의 선언이 "실행"될 때 처음 초기화 된다.

고유하기에 함수들이 공유하지만,  접근범위는 해당 스코프로 제한된다. 


1
2
3
4
5
6
7
8
9
void X1()
{
    static int a = 10;
 
    if (a)
        static int b = 20;
    else
        static int c = 30;
}
cs

X1()이 호출되어 3행을 실행하며 a가 초기화되고, 분기문을 통해 b가 초기화 된다. c는 초기화되지 않는다.



2. 전역 변수로 선언될 경우

해당 traslation unit (.cpp + #include한 .h)로  link범위가 한정된다.

일반적인 전역변수가 external linkage를 갖는다면 static 전역변수는 internal linkage다.

1
2
3
4
5
6
7
8
9
10
11
//somewhere.cpp
int a = 40;
static int b = 50;
 
int c() {
    return 60;
};
 
static int d(){
    return 70;
};
cs


어딘가의 cpp에 위와같이 정의되있다고 할 때 


1
2
3
4
5
6
7
8
9
10
11
12
13
extern int a;
extern int b;
 
extern int c();
extern int d();
 
int main()
{
    cout << a << endl;    //ok
    cout << b << endl;    //link error! 
    cout << c() << endl//ok
    cout << d() << endl//link error! 
}
cs.


a는 external 하기에 extern 키워드로 갖다 쓸 수 있는 반면

b는 internal해서 갖다 쓸수가 없다. 함수도 마찬가지다.

c++에서는 namespace로 해결되는 일이라, 더이상 사용할 일이 없는 C의 잔재인듯 하다. (stroustrup 교수님도 책에서 external 쓰지 말라고 하셨다)



3. 클래스의 멤버 변수로 선언될 경우

1
2
3
4
5
class Cstatic
{
public:
    static int a;
};
cs

1
2
3
#include "Cstatic.h"
 
int Cstatic:: a = 50;
cs


이런 방식으로 선언과 정의를 분리해서 해야하며, 정의는 클래스와 같은 스코프에 있어야 한다. 

이왕이면 cpp에 정의를 두는 게 헤더를 어딘가에서 #include 할 때 중복정의되는 문제를 피할 수 있다. (아니면 #ifndef)

다음과 같은 초기화는 에러다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma once
class Cstatic
{
public:
 
    Cstatic(int aa) 
        : a(aa)    //error
    {
        a = aa;    // 초기화가 아닌 대입이다.
    }
    ~Cstatic();
 
    static int a{ 50 };    //error
};
cs


그 이유는 Cstatic 타입의 객체를 만들 때마다 static int a를 50으로 초기화해서 생성한다는 건 뭔가 이상하지 않은가?

클래스 내의 static 변수는 객체의 인스턴스유무에 상관없이 (단 접근 지정자에 따라) 네임스페이스를 통해 접근할 수 있는 전역변수의 느낌이다.

같은 클래스의 인스턴스끼리는 공유해서 사용한다.

public일 경우 다음과 같이 접근해볼 수 있다.


1
2
3
4
5
6
int main()
{
    cout << Cstatic::a << endl;
    ++Cstatic::a;
    cout << Cstatic::a << endl;
}
cs


마찬가지로 static 멤버 함수도 네임스페이스를 통해 접근할 수 있는 함수의 느낌이다. 

단 클래스의 인스턴스가 없을 때에도 static 함수는 메모리에 올라가 있으므로, static 함수에서 non-static 변수의 사용은 불가하다.

즉 static 멤버함수에선 static 멤버변수만 사용 가능하다. 마찬가지로 같은 클래스의 모든 인스턴스들에서 공유해서 사용한다.


1
2
3
4
5
6
7
8
9
10
11
12
class Cstatic
{
public:
    static int a;
    int b;
    static void test()
    {
        ++a;
        ++b;    //error
    }
};
 
cs


4. 뭔가의 앞에 선언

그냥 보게되서 올림. 


1
2
3
4
5
6
7
static class Ctest
{
public:
    int a;
} tt;
 
static Ctest tt; //둘은  같다.
cs