79.2 정적 변수 선언하기

정적 변수를 알아보기 전에 먼저 자동 변수로 예제를 작성해보겠습니다. 다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

variable.c

#include <stdio.h>

void increaseNumber()
{
    int num1 = 0;    // 변수 선언 및 값 초기화

    printf("%d\n", num1);    // 변수 num1의 값을 출력

    num1++;    // 변수의 값을 1씩 증가
}

int main()
{
    increaseNumber();    // 0
    increaseNumber();    // 0
    increaseNumber();    // 0
    increaseNumber();    // 0: 변수가 매번 생성되고 사라지므로 0이 출력됨

    return 0;
}

실행 결과

0
0
0
0

함수 increaseNumber에 변수 num1을 선언한 뒤 0으로 초기화했습니다. 그리고 값을 출력한 뒤 ++ 연산자로 num1의 값을 1 증가시켰습니다.

이제 increaseNumber를 여러 번 호출해보면 0이 계속 출력됩니다. 즉, num1은 지역 변수이므로 increaseNumber를 벗어나면 값이 사라지며 다시 increaseNumber를 호출했을 때 이전 결과와는 상관없이 새로운 변수가 생성되기 때문입니다.

변수가 사라지지 않게 하려면 정적 변수를 사용해야 합니다. 정적 변수는 변수를 선언할 때 앞에 static 키워드를 붙입니다.

  • static 자료형 변수이름;

다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

static_variable.c

#include <stdio.h>

void increaseNumber()
{
    static int num1 = 0;     // 정적 변수 선언 및 값 초기화

    printf("%d\n", num1);    // 정적 변수 num1의 값을 출력

    num1++;    // 정적 변수 num1의 값을 1 증가시킴
}

int main()
{
    increaseNumber();    // 0
    increaseNumber();    // 1
    increaseNumber();    // 2
    increaseNumber();    // 3: 정적 변수가 사라지지 않고 유지되므로 값이 계속 증가함

    return 0;
}

실행 결과

0
1
2
3

여기서는 변수 num1을 선언할 때 static 키워드를 붙여서 정적 변수로 만들었습니다. 이제 increaseNumber를 여러 번 호출해보면 0 1 2 3과 같이 출력됩니다. 즉, 정적 변수는 함수를 벗어나더라도 변수가 사라지지 않고 계속 유지되므로 ++ 연산자가 적용되어 값이 계속 증가하게 됩니다.

static int num1 = 0;은 프로그램이 시작될 때 변수를 초기화하며 increaseNumber 함수가 호출될 때는 변수를 초기화하지 않고 무시합니다. 이를 코드로 풀어보면 다음과 같습니다.

void increaseNumber()
{ //            ↓ 0
    static int num1 = 0;    // 프로그램이 시작될 때 정적 변수가 생성되고 초기화됨
    num1++;                 // 0에서 1로 증가
}

void increaseNumber()
{ //            ↓ 1
    static int num1 = 0;    // 다시 함수가 호출될 때는 값 초기화 무시
    num1++;                 // 1에서 2로 증가
}

void increaseNumber()
{ //            ↓ 2
    static int num1 = 0;    // 다시 함수가 호출될 때는 값 초기화 무시
    num1++;                 // 2에서 3으로 증가
}

void increaseNumber()
{ //            ↓ 3
    static int num1 = 0;    // 다시 함수가 호출될 때는 값 초기화 무시
    num1++;                 // 3에서 4로 증가
}

여기서 num1은 정적 변수이면서 지역 변수인데 increaseNumber 함수 블록(범위)을 벗어나도 사라지지 않아서 정적 변수이고 increaseNumber 함수 블록(범위) 안에서만 접근할 수 있어서 지역 변수입니다.

그럼 전역 변수를 정적 변수로 만들면 어떻게 될까요? 전역 변수는 정적 변수가 아니더라도 값이 계속 유지되지만 외부에서 사용할 수 있느냐 없느냐의 차이가 있습니다. 다음 내용을 프로젝트 디렉터리에 print.c로 저장하세요(반드시 프로젝트에 포함해야 합니다).

print.c

#include <stdio.h>

static int num1 = 10;

void printNumber()
{
    printf("%d\n", num1);    // 10: 정적 전역 변수 num1의 값 출력
}

이제 main 함수가 있는 소스 파일입니다. 다음 내용을 프로젝트 디렉터리에 main.c로 저장하세요.

main.c

#include <stdio.h>

extern int num1;    // 다른 소스 파일(외부)에 있는 정적 전역 변수는 extern으로 사용할 수 없음
                    // 컴파일 에러

int main()
{
    printf("%d\n", num1);     // 정적 전역 변수 num1의 값 출력

    return 0;
}

컴파일 결과

fatal error LNK1120: 1개의 확인할 수 없는 외부 참조입니다.

static으로 선언한 변수를 extern으로 사용하려고 하면 컴파일(링크) 에러가 발생합니다. 즉, 정적 전역 변수는 자신이 선언된 소스 파일 안에서만 사용할 수 있고, 외부에서는 가져다 쓸 수 없습니다. 즉, 전역 변수에 static을 붙이면 변수의 범위를 파일 범위로 제한하는 효과를 냅니다.

그림 79‑1 정적 전역 변수는 외부에서 사용할 수 없음

extern int num1; 대신 extern static int num1;과 같이 만들더라도 컴파일 에러가 발생합니다. 즉, 잘못된 문법입니다.

이번에는 정적 변수의 초깃값에 대해 알아보겠습니다. 다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

static_variable_initialized_zero.c

#include <stdio.h>

static int num1;    // 정적 변수는 초깃값을 지정하지 않으면 0이 들어감(전역 변수)

int main()
{
    static int num2;     // 정적 변수는 초깃값을 지정하지 않으면 0이 들어감(지역 변수)

    printf("%d\n", num1);    // 0
    printf("%d\n", num2);    // 0

    return 0;
}

실행 결과

0
0

정적 변수는 초깃값을 지정하지 않으면 0으로 초기화됩니다. 특히 정적 변수를 전역 변수로 선언했든 지역 변수로 선언했든 상관없이 초깃값을 지정하지 않으면 0으로 초기화됩니다. 그리고 정적 변수(전역, 지역)는 프로그램이 시작될 때 생성 및 초기화되고 프로그램이 끝날 때 사라집니다.

참고 | 정적 변수와 매개변수

정적 변수는 함수의 매개변수로 사용할 수 없습니다. 매개변수에 static을 붙이더라도 매개변수는 정적 변수가 되지 않으며 값이 유지되지 않습니다.

void increaseNumber(static int num1)    // 정적 변수는 매개변수로 사용할 수 없음. 잘못된 문법
{                                       // warning C4042: 'num1': 저장소 클래스가 잘못되었습니다.
    printf("%d\n", num1);
    num1++;
}