본문 바로가기
Code/C

c언어 정적변수, 지역변수, 전역변수 비교 (static, local, global)

by 코드포휴먼 2020. 12. 25.

함수 내에서 사용하는 변수로서 지역변수, 전역변수, 정적변수의 차이를 알아본다.

 

[전체 요약]

☑️ 지역변수(local variable, 자동변수)는 중괄호 내부, 함수의 매개변수(Parameter)에서 사용되는 변수를 의미한다.

지역변수의 지역함수의 내부, 중괄호 내부를 의미한다.

따라서 함수 안에서만 접근 가능하며, 함수를 벗어나면 사라진다 (= 변수의 메모리 공간이 소멸된다).

지역변수는 초기화하지 않으면 컴파일 에러가 나거나 쓰레기값이 저장된다.

더보기

지역변수(local variable)는 자동변수(auto variable)와 같다.

자동변수는 흔히 블록(중괄호) 안에서 사용하는 변수로서, 변수가 생성된 뒤에 자동으로 사라진다고 하여 자동변수라고 부른다.
매우 흔히 사용하기 때문에 auto 키워드를 생략하고 사용한다.

 

☑️ 전역 변수(global variable)지역변수와 반대로 중괄호 외부에 선언되는 변수다.

전역이라는 이름 그대로 어느 지역에서든 참조해서 사용할 수 있다.

전처리기 밑에 선언하며, 반드시 상수로 초기화 해야한다.

초깃값을 지정하지 않으면 디폴트값 0으로 자동 초기화 된다.

 

전역변수는 모든 곳에서 접근이 가능하고, 프로그램 종료 전엔 메모리가 소멸되지 않는 장점이 있지만

잘못 사용하거나 남용할 경우 관리가 어려워질 수 있다. (유지 보수, 재사용 등)

이를 부분적으로 보완한것이 정적변수다.

 

☑️ 정적변수(static variable)는 프로그램이 종료되기 전까지 메모리가 소멸되지 않는 변수다.

함수를 벗어나도 변수가 사라지지 않고 유지된다. 

초기화할 때 반드시 상수로 초기화 해야한다.

초깃값을 지정하지 않으면 디폴트값 0으로 자동 초기화 된다.

 

여기까지는 전역변수와 동일하지만, 차이점은 초기화가 딱 한번만 진행된다는 것이다.

정적변수는 프로그램이 시작될 때 생성 및 초기화 되고 프로그램이 끝날 때 사라진다. 

또한 함수의 매개변수로 사용할 수 없다는 특징이 있다.

 

정적변수는 사용범위에 따라 정적 지역변수정적 전역변수로 나뉜다.

정적 지역변수(static local variable)중괄호 내부에서만 사용할 수 있고, 한번 초기화 되면 이후에 함수 호출 시 값의 초기화를 무시한다.

정적 전역변수(static global variable)자신이 선언된 소스 파일에서만 사용할 수 있고, 외부에서는 가져다 쓸 수 없다.

전역변수에 static을 붙이면 변수의 범위를 파일 범위로 제한하는 효과를 내기 때문이다.

 

 

[전체 표 비교]

  지역변수 (local variable) 전역변수 (global variable) 정적변수 (static variable)
메모리 생성 시점 중괄호 내부 프로그램 시작 프로그램 시작
메모리 소멸 시점 중괄호 탈출 프로그램 종료 프로그램 종료
디폴트 초깃값
(초기화하지 않을 시)
쓰레기값 저장 자동 0초기화 자동 0초기화
(초기화는 한번만 진행)
사용범위 중괄호 내부 프로그램 전체 - 정적 지역변수
(static local variable)

: 중괄호 내부

- 정적 전역변수
(static global variable)

: 선언된 소스 파일
메모리 할당공간 Stack 영역 Data 영역 (초기화)
BSS 영역 (비초기화)
Data 영역 (초기화)
BSS 영역 (비초기화)

참고로 전역변수와 정적변수는 값을 초기화했으면 Data 영역에 생성되고, 초기화하지 않았으면 BSS 영역에 생성되고 0이 들어간다.

0이 자동으로 들어가는 이유와 메모리에 관한 내용은 이 포스팅을 참고한다.

 

 

[예시 - 지역변수 (local variable)]

먼저 지역변수를 코드로 확인해본다. (코드출처: 코딩도장)

#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;
}

 

increaseNumber 함수 안에서 선언한 num1은 지역 변수이므로 increaseNumber를 벗어나면 값이 사라지며

다시 increaseNumber를 호출했을 때 이전 결과와는 상관없이 새로운 변수가 생성되기 때문에

increaseNumber를 여러 번 호출해보면 0이 계속 출력된다.

 

 

또 다른 지역변수 예시를 보자. (코드출처: 파일의IT블로그)

#include <stdio.h>

void print(){
	int a = 30, b = 40;
	printf("%d %d \n", a, b);
}
int main(){
	int a = 10, b = 20;
	printf("%d %d \n", a, b);
	print();
    return 0;
}

/* 결과값 */
// 10 20
// 30 40

두 번째 예시에서는 print 함수에서도 a 와 b 를 선언, main 함수 내부에서도 a 와 b를 선언해서 출력하고 있다.

각각의 a와 b는 중괄호 내부에서 실행되는 지역변수기 때문에 이름은 같지만 지역적으로 전혀 다른 변수다.

각자 print 함수의 중괄호, main 함수의 중괄호 지역에서 별개로 실행되는 것이다.

 

 

함수의 매개변수도 마찬가지다.

위의 코드에서 print 함수의 지역변수를 매개변수로 바꿔보았다.

#include <stdio.h>

void print(int a, int b){
	printf("%d %d \n", a, b);
}

int main(){
	int a = 10, b = 20;
	printf("%d %d \n", a, b);
	print(30, 40);
	return 0;
}

/* 결과값 */
// 10 20
// 30 40

print 함수의 매개변수로 선언된 a, b와 main 함수 안에 선언된 a,b는 서로 영향을 끼치지 않는다.

지역(중괄호)에서 메모리를 생성하고, 해당 지역을 빠져나가게 되면(중괄호 탈출) 메모리가 자동으로 소멸된다.

<코드 메모리 흐름>
1. main 함수에서 a, b 를 위한 메모리 공간이 생성된다.
2. print(30,40) 이 호출되어 매개변수 a,b 를 위한 메모리 공간이 생성된다.
3. a = 30, b = 40이 대입된다.
4. print 함수에서 a와 b를 출력한 후 함수가 종료되면 매개변수 a,b의 메모리 공간이 소멸한다.
5. main 함수가 종료된 이후 main 함수의 a , b 를 위한 메모리 공간이 소멸한다.

 

 

[예시 - 전역변수 (global variable)]

역변수 예시를 보자. (코드출처: 파일의IT블로그)

#include <stdio.h>
int global = 100;
	
int main(){
	printf("%d", global);
	return 0;
}

/* 결과값 */
// 10

전역변수의 선언은 전처리기 밑에 적어주면 된다.

전역변수는 메모리 생성시점프로그램의 시작, 소멸시점이 프로그램의 종료다.

그렇기에 프로그램이 실행되는 동안에는 어디서든 접근해서 사용할 수 있다.

 

 

지역변수는 초깃값을 지정하지 않으면 쓰레기값이 저장되지만,

반면에 전역변수는 자동으로 0으로 초기화 된다.

#include <stdio.h>
int global;
	
int main(){
	printf("%d", global);
	return 0;
}
	
/* 결과값 */
// 0

 

전역변수의 초기화는 반드시 상수로 해야한다는 점을 주의하자.

#include <stdio.h>
int number = 100
int global = number;   //에러 발생
	
int main(){
	printf("%d", global);
	return 0;
}

수정이 가능한 심볼릭 상수라고 이해하면 좋다. (물론 상수처럼 초기화가 의무적이진 않다.)

 

 

아래는 전역변수의 특징을 보여주는 예시다. 어떤 함수에서든 접근해서 사용한다.

#include <stdio.h>
void add();
int global;
	
int main(){
	printf("%d \n", global);
	add();
	printf("%d", global);
	return 0;
}

void add(){
	global += 100;
}

/* 결과값 */
// 0
// 100

 

 

[예시 - 정적 지역변수 (static local variable)]

정적변수는 선언할 때 static 키워드를 앞에 명시하면 된다.

먼저 지역변수이자 정적변수를 선언해서 결과를 확인해본다.  (코드출처: 코딩도장)

지역변수는 중괄호 탈출시에 메모리가 소멸하므로 값을 누적시킬 수 없지만, 이를 정적변수의 특성으로 해결한 예시다.

#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;
}

지역변수 num1을 선언할 때 static 키워드를 붙여서 정적 변수로 만들었다. 초깃값을 지정해주지 않으면 자동으로 0이 들어간다.

이제 increaseNumber를 여러 번 호출해보면 0 1 2 3과 같이 출력된다.

즉, 정적 변수는 함수를 벗어나더라도 변수가 사라지지 않고 계속 유지되므로 ++ 연산자가 적용되어 값이 계속 증가한다.

정적변수 num1은 프로그램이 시작할 때 0으로 초기화되며 increaseNumber 함수가 호출될 때는 변수를 초기화하지 않고 무시한다.

따라서 일정 지역 안에서 전역변수와 유사한 역할을 수행한다.

위에서 num1은 지역변수이면서 정적변수인데, increaseNumber 함수 블록(범위)을 벗어나도 사라지지 않아서 정적변수고 

increaseNumber 함수 블록(범위) 안에서만 접근할 수 있어서 지역변수다.

 

 

정적 지역변수는 엄밀히 따지면 지역변수이기 때문에 중괄호를 벗어난 다른 함수에서 접근하지 못한다.

아래의 경우 에러가 발생한다.

#include <stdio.h>

void increaseNumber(){
    static int num1;
    printf("%d \n", num1); 
    num1++;
}

int main(){
    increaseNumber();    // 0
    increaseNumber();    // 1
    increaseNumber();    // 2
    printf("%d\n", num1);   // 에러 발생
    
    return 0;
}

main 함수는 increaseNumber 함수 내부에 선언된 정적 지역변수 num1의 값을 사용할 수 없다. 

 

 

[예시 - 정적 전역변수 (static global variable)]

이번엔 전역변수이자 정적변수를 선언해본다. 

아래의 코드는 전역변수이자 정적변수로 선언한 num1을 외부 파일 main.c에서 사용한 코드다.  (코드출처: 코딩도장)

/* print.c */
#include <stdio.h>
static int num1 = 10;

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


/* main.c */
#include <stdio.h>
extern int num1;    // 다른 소스 파일(외부)에 있는 정적 전역 변수는 extern으로 사용할 수 없음
                    // 컴파일 에러

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


/* 컴파일 결과값 */
fatal error LNK1120: 1개의 확인할 수 없는 외부 참조입니다.

 

extern 키워드로 선언한 외부 변수는 외부 파일에 선언된 변수를 참조하는 외부변수다. 여기서 외부파일에 선언된 변수는 전역변수다.

그러나 static으로 선언된 변수는 자신의 파일에서만 접근할 수 있어서 컴파일(링크) 에러가 난다.

사진 출처 코딩도장 https://dojang.io/mod/page/view.php?id=690

만약 print.c의 정적 전역변수 num1을 static 키워드 없이 단순한 전역변수로 선언했다면

외부파일인 main.c에서 extern 키워드를 통해 사용할 수 있다. 

단, 외부변수의 이름은 가져올 변수의 이름과 동일해야 한다.

 

 

한편 정적변수는 함수의 매개변수로 사용할 수 없다는 특성이 있다.

매개변수에 static을 붙이더라도 매개변수는 정적 변수가 되지 않으며 값이 유지되지 않는다.

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

 

 

지금까지 정적변수, 지역변수, 전역변수의 개념을 C언어로 다루어보았다.

 

 


출처

C언어 정적변수

코딩도장 정적변수 dojang.io/mod/page/view.php?id=690

코딩도장 정적함수 dojang.io/mod/page/view.php?id=691

위키피디아 ko.wikipedia.org/wiki/%EC%A0%95%EC%A0%81_%EB%B3%80%EC%88%98

파일의IT블로그 pgh268400.tistory.com/82

 

C언어 자동변수

코딩도장 자동변수 dojang.io/mod/page/view.php?id=803

 

심볼릭 상수

파일의IT블로그 pgh268400.tistory.com/19?category=1072473

댓글