포스트

[1일 1블로그 무사고 4일] C++ static에 대해서

static이란?

static은 변수와 함수의 생명 주기와 사용 범위를 지정하는 방식 중 하나로서, static으로 선언된 변수나 함수는 다음과 같은 특징을 가진다

  • 생명 주기 : 프로그램이 시작할 때 생성되고 프로그램이 종료될 때 소멸됨
  • 사용 범위 : 변수나 함수가 선언된 범위 내에서 사용, 전역 혹은 지역으로 구분

static으로 변수를 선언하면 프로세스의 데이터 메모리 영역에 생성되어 프로그램이 종료될 때 까지 생명을 유지한다.

static 전역 변수

함수 외부에 선언된 static 변수를 static 전역 변수라고 한다. 생명 주기는 프로그램이 시작될 때 생성 및 초기화, 프로그램이 종료될 때까지 유지
이 속성은 extern을 사용하는 일반 전역 변수와 같지만(만약 extern 키워드를 사용하지 않고 그냥 전역 변수를 선언해도 암시적으로 extern 선언이 된다) 전역 변수와 달리 소스 파일 단위 접근 범위를 가진다

static vs extern 전역 변수

위에서 말한 소스 파일 단위 접근 범위가 무엇일까?
변수에는 링크라는 속성이 있다. 이는 같은 이름을 가진 경우 같은 식별자를 참조하는지를 결정한다.
링크가 없는 변수는 정의된 제한된 범위에서만 참조할 수 있다. 함수 내에서 생성된 로컬 변수가 링크 속성이 없는 대표적인 예이다. 함수 내에 생성된 로컬 변수의 경우 같은 이름을 가지더라도 다른 함수에서 선언되면 각각 독립적인 변수로 취급됨

링크
C++ 프로그램을 컴파일하면 C++ 소스파일 별로 독립적인 오브젝트 파일이 생성되고 이 오브젝트 파일들을 하나로 연결(linking)하여 실행 파일을 만들어 낸다. 이 때 함수나 변수들의 이름을 기준으로 함수 호출, 변수 참조 등을 연결하는데 같은 소스 파일 내에서 연결 되는 되는 경우 ‘내부 링크’라고 하고 외부 소스 파일과도 연결하는 것을 ‘외부 링크’라고 한다. 일반적으로 함수나 전역 변수는 외부 링킹이 적용 되지만 명시적으로 static을 적용하는 경우 내부 링크만 적용 된다.
출처: https://kukuta.tistory.com/434 [HardCore in Programming:티스토리]

이 개념을 확장해 전역으로 선언된 변수의 경우 내부 링크만을 가지거나 외부 링크를 가진 변수로 나눌 수 있다.
static으로 선언된 전역 변수의 경우 내부 링크만을 가지며, extern 전역 변수의 경우 외부 링크까지 가진다.
내부 링크만을 가진 static 전역 변수는 소스 파일 단위의 전역 변수로써 파일 어디에서든 접근하여 값을 읽거나 수정할 수 있지만 다른 소스파일에서는 다른 변수로 취급이 된다
반면 extern 전역 변수는 이름 그대로의 전역 변수로써 프로그램 어디서든 접근 가능하다.

전역 변수 초기화를 이용한 트릭

전역 변수의 특성을 이용해 main 함수 이전에 함수를 호출할 수 있는 트릭을 살펴보자
main 함수가 호출 되기 전 다른 함수들을 호출할 수 있는 방법이 존재하는데 바로 전역 변수 초기화를 이용하는 것임
전역 변수는 단순 값으로도 초기화가 되지만, 초기화를 위해 함수를 호출하는 것이 허용이 된다!
소스 파일 단위에서만 접근 가능한 static 전역 변수의 특성이 여기서 빛을 발함. 전역 변수이기에 초기화를 위해 함수 호출을 할 수 있지만, 같은 이름을 가지더라도 다른 소스 파일에서 다른 변수로 취급되어 이름 충돌이나 다른 소스 파일에서 해당 변수를 참조할 일이 없다.

static 로컬 변수

함수 내부에 선언된 static 변수를 로컬 static 변수라고 한다. 로컬 static 변수의 생성과 초기화는 코드에서 변수 선언이 처음 호출되는 시점이며, 프로그램이 종료될 때 까지 유지한다.

  • 초기화는 함수가 호출될 때 처음 한번만 진행한다
  • 함수가 종료 되더라도 변수가 파괴되지 않고 프로그램이 종료될 때까지 값을 유지한다
  • 로컬 static 변수는 선언된 함수 내에서만 접근할 수 있다

static 함수

static 키워드는 변수 뿐 아니라 함수에도 적용 가능함

1
2
3
static <type> <name>(<arguments>)
{
}

static 전역 변수와 비슷한 링크 속성을 가진다. 즉, 동일 소스 파일 내에서는 어디에서든 접근과 호출이 가능하지만 다른 소스 파일에서는 접근이 불가능하며, 같은 이름을 가지고 있더라도 다른 소스 파일에 있는 경우 다른 별도의 함수로 취급 된다
static 함수는 소스 파일 내에서만 정의해 사용할 것을 권장한다. 헤더에 static 함수를 개별 정의해 사용하는 방법은 잘 사용되지 않아 익숙치도 않고 함수를 사용하는 측에서 별도의 함수를 꼭 정의해야 하는 불편함, 같은 이름을 가진 함수임에도 호출 되는 소스 파일의 위치에 따라 다른 동작을 하기에 코드 분석에 많은 어려움을 가져다 준다. 쓰지 말자!!

클래스에서의 static 키워드

static 멤버 변수

클래스 내 static으로 선언된 멤버 변수는 특정 객체에 종속되지 않고 해당 클래스의 모든 객체들에게 공유 된다. 그래서 static 멤버 변수는 생성자에서 초기화될 수 없고, 클래스 외부에서 별도 초기화 과정이 필요함!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
{
  public:
    static int num;

}

int A::num = 0;  // 이렇게 초기화해야함, main에서 초기화하면 오류

int main()
{
  A a;
...
}

static 멤버 변수에 접근하는 방법은 두 가지가 있는데 클래스 이름을 사용해 접근하는 방법을 권장한다.

1
2
A::num = 2;  // 클래스 이름을 사용해 접근하자
a.num = 2;

static 클래스 객체

클래스 객체를 선언할 때 static으로 선언하면 다른 static과 비슷하게 전역인지, 로컬인지에 따라 생성 시점이 다르고 소멸 시점은 프로그램이 종료될 때 소멸된다

static 클래스 멤버 함수

static 멤버 변수와 마찬가지로 클래스 객체에 종속되지 않음. 클래스 네임과 :: 연산자를 이용해 호출하는 것을 권장함
static 멤버 함수는 클래스 객체에 종속된 것이 아니므로 함수 내부에서 클래스 객체에 종속되는 일반 멤버 변수 또는 멤버 함수는 접근 불가능하다. 하지만 static 멤버 변수나 static 함수는 접근 가능하다

static 멤버 함수는 virtual 함수가 될 수 없으며 const 또는 volatile 한정자를 적용할 수 없다

출처

블로그

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.