일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- queue
- arduino compiler
- LineTracer
- C언어
- set
- list
- Algorithm
- Stack
- vector
- Arduino
- WinAPI
- 아두이노 소스
- map
- stl
- html
- 통계학
- 시스템프로그래밍
- priority_queue
- directx
- c++
- 수광 소자
- Deque
- 아두이노
- 컴퓨터 그래픽스
- 아두이노 컴파일러
- Array
- 자료구조
- Visual Micro
- 라인트레이서
- 운영체제
- Today
- Total
Kim's Programming
기억 부류(Storage Class) (1/2) 본문
전역변수와 지역변수
기억 부류(Storage Class)란 변수가 저장되는 위치에 따라서 정해지는 변수의 여러가지 성질을 의미합니다. 변수가 어디에 생성 되는가? 에 따라서 변수의 통용범위와 파괴시기들이 정해지게 됩니다. 기억 부류는 4가지가 있는데 표를 통해 알아보겠습니다.
기억 부류 |
전역 변수 |
지역 변수 |
정적 변수 |
레지스터 변수 |
지정자 |
extern |
auto |
static |
register |
저장 장소 |
정적 데이터 영역 |
스택 |
정적 데이터 영역 |
CPU의 레지스터 |
선언 위치 |
함수의 외부 |
함수의 내부 |
함수의 내부 |
함수의 내부 |
통용 범위 |
프로그램 전체 |
함수의 내부 |
함수의 내부 |
함수의 내부 |
파괴 시기 |
프로그램 종료시 |
함수 종료시 |
프로그램 종료시 |
함수 종료시 |
초기값 |
0으로 초기화 |
초기화 되지 않음 |
0으로 초기화 |
초기화 되지 않음 |
표에 많은 기억 부류들이 있지만 이 중에서 전역 변수와 지역변수가 가장 중요하며 두가지에 대해서 먼져 예쩨를 통해서 알아보도록 하겠습니다. 우선 간단한 예제 보고 가겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
#include<stdio.h>
void function();
int global; //전역 변수 선언
//함수의 외부에 선언
void main()
{
int local = 0;//지역 변수 선언
//변수 선언
global = 1;//변수 접근 가능
local = 4;//변수 접근 사능
}
void function()
{
global = 5;//변수 접근 가능
local = 4;//변수 접근 불가
} |
cs |
다음 소스를 이용하여 전역 변수와 지역 변수의 차이를 알아보겠습니다.
- 변수의 선언 위치가 다릅니다. 전역 변수와 지역변수의 가장 큰 차이점인데 전역변수 함수 바깥에서 선언하고 지역변수는 함수 내부에 선언합니다. 위 예제에 local은 함수내부에서 선언된 변수이기 떄문에 지역 변수이고 global은 함수 밖에서 선언 되었기 때문에 전역 변수입니다.
- 변수의 선언 위치도 다르지만 변수의 통용 범위도 다릅니다. 통용범위라 함은 변수가 사용 될 수 있는 범위를 의미합니다. 전역변수는 특정한 함수 내부에 있지 않기 때문에 어느 함수에도 속하지 않고 프로그램 전체가 공유하게 됩니다. 그렇기 때문에 변수가 선언된 위치이후의 어디에서든 사용이 가능하게됩니다. 위의 소스에서 global은 main함수에서도 function 함수에서도 이상없이 사용이 가능합니다. 하지만 C언어는 1패스 방식의 컴파일러를 가지고 있기 때문에 꼭 선언 된 다음부터 사용이 가능합니다. 이와 다르게 지역변수는 함수 내부에 종속 되어 있기 떄문에 함수 내부에서만 사용이 가능하며 다른 함수에서는 사용이 불가능합니다. 어떠한 방법을 써도 사용은 불가능합니다. 지역변수는 함수 내부에서 변수의 역할이 끝나면 버려집니다. 함수의 각개 자신이 가진 지역변수는 사용이 가능하지만 다른 함수의 지역 변수는 사용 할수 없습니다.
- 변수의 파괴 시기가 다릅니다. 변수는 값을 기억하기 위해 메모리를 할당 받아서 사용하게됩니다. 변수는 다 사용 하면 파괴가 되게 되는데 변수가 파괴된다는 말은 변수가 차지하고 있던 메모리를 회수한다는 말입니다. 시스템 메모리가 무한하지 않기 떄문에 변수는 필요시에만 메모리를 차지하여 다음을 위하여 자리를 내주어야합니다. 변수의 메모리가 회수되는 순간 변수의 존재는 없어지게 됩니다. 하지만 전역변수는 프로그램에 소속되어 있고 다른 함수에서 사용이 가능해야하기 떄문에 프로그램이 실행중인 동안에는 파괴되지 않습니다. 실행 직후에 생성이 되며 프로그램이 실행되는 동안에는 메모리를 계속 차지하고 있고 프로그램 종료시에 파괴가 되게 됩니다. 이와는 또 다르게 지역변수는 특정 함수안에 종속 되어 있기 떄문에 함수가 실행중일때만 메모리를 차지하며 함수가 끝나면 변수의 생명도(메모리 회수) 끝이 나게 됩니다. 또한 함수의 역할에만 쓰이기 때문에 함수가 끝나면 필요도 없어집니다. 따라서 지역변수는 함수의 역할이 끝나면 소멸하게 됩니다. 하지만 함수가 또 다시 호출되는 경우 생성되고 또 파괴되고를 반복합니다.
- 변수가 생성되는 기억장소가 다릅니다. 전역변수는 한 번 정해진 메모리 위치에 계속 남아야하기 떄문에 정적 데이터 영역에 생성됩니다. 정적 데이터 영역이란 실행파일의 한 부분으로 프로그램이 실행될떄 메모리로 로드되어 계속 유지되게 됩니다. 지역변수는 프로그램 실행중에 생성, 파괴를 반복하므로 스텍에 생성됩니다. 스택(Stack)이란 데이터의 임시저장소로 알아두면 되겠습니다.)
- 초기화 여부가 다릅니다. 전역변수는 별도의 초기식을 지정하지 않더라도 0으로 초기화 됩니다. 위 소스에서의 global은 특별한 초기화를 시키지 않더라도 생성후엔 0이 되게 됩니다. 뭐 물론 일반 변수들 처럼 int global=7;등으로 초기화를 다른 값으로 시킬 수도 있습니다. 전역변수는 프로그램 전체에서 사용을 하는 변수이기 떄문에 컴파일러가 진작에 오류를 발생시킬 수 있는 쓰레기값을 진작에 초기화를 이용해서 없애 주는 것입니다.
지역변수의 장점
지역변수는 함수 내부에서만 사용할 수 있고 함수가 끝나면 파괴가 되는데 비해 전역 변수는 모든 함수에서 자유롭게 사용할 수 있고 프로그램이 실행중인 동안에는 계속 유지되게 됩니다. 통용 범위도 넓고 지속시간도 길고 지역변수가 할 수 있는 대두분의 일을 대체할 수 있습니다. 하지만 이렇다면 전역변수를 사용하지 지역변수는 사용 하지 않을 것입니다. 하지만 그럼에도 불구하고 지역변수를 사용하는데 지역변수의 장점에 대해서 알아보도록 하겠습니다.
- 함수의 독립성을 높힐 수 있습니다. 프로그램은 함수로 구성되고 함수는 프로그램의 부품이라고 할 수 있습니다. 부품은 특별한 경우를 제외하고는 독립적으로 작동할 수 있어야 재활용하기가 좋습니다. 부품끼리 서로 공유하게 되면 서로서로 서로 얽히게 되어 구조가 복잡하게 되버립니다.
- 지역변수는 디버깅 효율을 향상시킵니다. 버그들이 대부분 변수로부터 발생하게되는데 만약 전역변수를 남발하게되면 전역변수 전체를 다 살펴보아야하는 경우가 생깁니다. 하지만 지역변수는 함수내에서 선언된 지역변수만 살펴서 디버그를 하면 되기 떄문에 상대적으로 빠르게 디버깅을 할 수 있습니다.
- 지역변수는 메모리를 절약하게 됩니다. 전역변수는 프로그램이 실행될때 같이 생성되어 계속 값을 유지해야 하므로 그만큼의 메모리를 항상 차지하게 됩니다. 지역변수는 함수가 호출될 때만 생성되며 함수가 종료되면 즉시 파괴되므로 자신이 속해 있는 함수가 실행중일 때만 메모리를 차지합니다. 그래서 전역변수 대신 지역변수를 많이 쓰게 되면 메모리를 상대적으로 적게 쓸 수 있습니다.
- 재귀 호출이나 상호 호출 같은 기법은 지역 변수가 있어야만 사용할 수 있습니다. 이런 기법들은 함수가 호출떄 마다 새로운 변수가 생성되어야만 가능한 기법입니다. 재귀 호출이 가능하기 위해서는 각 호출시마다 고유의 값을 유지해야 하는데 전역변수로는 이런 기법구사가 불가능합니다.
지역변수는 전역변수에 비해 월등히 많은 장점을 가지고 있습니다. 전역변수는 편리하지만 복잡한 문제를 일으킬 수 있기 떄문에 전역변수의 사용은 가급적 자재하는 것이 좋습니다. 전역변수를 사용하지 않고 프로그램 작성이 가능하다는 것은 수학적으로도 증명이 되어있습니다. 하지만 그렇다고 아예 사용하지 않는 것은 좋지 않고 적절하게 이용하여 사용하면 논리구조를 간단하게 만들어 주기도 합니다.
외부변수
앞에서 변수에 대해서 쓸떄 변수의 선언을 int number (타입 변수명)으로 한다고 하였는데 더 정확히 하면 다음과 같이 됩니다.
[지정자] 타입 변수명;
지정자(Specifier)는 기억 부류를 비롯하여 상수 지정, 최적화 금지 등 변수의 여러 가지 성질을 지정하는 키워드인데 필요없을 경우 생략할 수도 있습니다. 기억 부류를 지정할 떄는 auto, extern, static, register 등의 키워드를 사용하는데 먼저 지역변수를 지정하는 auto 키워드에 대해 알아보겠습니다. 지역변수로 선언할 떄는 타입 앞에 auto 키워드를 붙이게 됩니다.
1
2
3
4 |
int CalcSum(int bound)
{
auto int i, sum;
} |
cs |
이렇게 선언하게 되면 변수 i 와 sum은 지역변수가 됩니다. 지역변수 지정자의 이름이 auto인 이유는 함수가 호출될 떄 지역변수가 자동으로 생성되고 함수가 종료될 때 자동으로 파괴되기 때문입니다. 그래서 c에서는 지역변수를 자동변수(Automatic Variable)이라고 부릅니다. 지역변수는 함수 내부에서만 선언할수 있으므로 함수 외부에서 auto 지정자를 넣게 되면 에러로 처리됩니다. 사실 현실적으로 auto 키워드를 거의 이용하지않는데 지정자를 생략하면 디폴트로 auto가 되기 때문입니다. 그래서 auto int i;는 int i;와 동일한 의미를 가지며 수식어가 있으면 int를 생략할 수 있는 규칙에 따라 auto i;도 같은 선언문이 되게 됩니다. 이는 마치 +2, +3을 표기할떄 앞에 부호를 붙이지 않않고 생략해도 부호 +를 가지고 있다는 것과 같은 의미 입니다. 아무 지정자 없이 변수를 선언하면 변수가 선언된 위치에 따라서 기억 부류가 결정됩니다.
- 함수 내부에서 : auto로 인식하여 지역변수가 됩니다.
- 함수 내부에서 : 전역변수로 선언됩니다.
다음 extern 이라는 지정자를 알아보도록 하겠습니다. extern 이라는 키워드는 변수가 외부 어딘가에 선언되어 있다는 것을 알리는 역할을 하게되는데 auto보다 사용법이 조금은 복잡합니다. 소스를 보면서 알아보겠습니다.
1
2
3
4
5
6
7
8
9
10 |
#include<cstdio>
int i=15;
void main()
{
extern int i;
extern int j;
printf("i == %d\n",i);
printf("j == %d\n",j);
}
int j=17; |
cs |
이 소스에서 i와 j는 모두 main 함수 밖에 선언하였기 때문에 전역변수 입니다. main에서 함수 외부에 있는 함수들을 사용하기 위하여 extern 선언을 하였고 main 함수에서 필요한 i변수와 j변수는 함수 밖에 있는 것을 이용하겠다는 것을 말합니다. 하지만 extern 지정자는 다음과 같은 경우에는 생략이 가능합니다. 함수보다 앞쪽에 선언되어 있는 외부 변수는 extern을 이용하지 않아도 이미 컴파일러가 변수에 대해서 파악을 했기 떄문에 선언 해줄 필요가 없습니다. 이 규칙에 따라 앞에 있는 i 변수는 extern 생략이 가능합니다. 하지만 j변수는 컴파일러가 파악이 미리 안된 변수이기 떄문에 생략이 불가능 합니다. 물론 일반적으로는 전역변수는 위쪽에 선언해버리기 떄문에 extern지정자를 잘 사용하지도 않고 많약 순서가 달라 사용해야하는 경우에는 그냥 앞쪽으로 몰아버리면 됩니다. 하지만 외부 모듈을 불러오는 경우에는 이를 사용 하는 경우가 많습니다.
정적변수
정적변수(static Variable)은 전역변수와 지역변수의 성격을 동시에 가지게 되는 기억부류입니다. 위쪽 표에 있는 특징들을 살펴보면 저장장소는 전역변수의 특징을 가지고 토용ㅇ 범위는 지역변수라고 할 수 있습니다. 정적변수를 선언할 때는 반드시 static 이라는 지정자를 앞에 붙여줘야 합니다.
static int integar;
statc double d;
이렇게 선언하면 integar나 d라는 변수는 정적 변수가 되어 정적 데이터 영역에 저장이 되며 통용범위는 선언문이 있는 함수내부로 국한되게 됩니다. 특정 함수만 사용하되 그 값을 계속 유지할 필요가 있을 때 정적변수를 사용합니다. 다음 예시를 통해서 알아보도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
#include<cstdio>
void Print_Count();
void main()
{
for (int i = 0; i < 5; i++)
{
Print_Count();
}
}
void Print_Count()
{
static int count = 0;
count++;
printf("%d 번쨰 반복입니다.\n", count);
}
|
cs |
이 예제에서는 for문이 돌아가면서 그 횟수를 세는 소스입니다. 하지만 함수안에 지역변수는 함수가 호출되고 종료되는 순간에 파괴되어 변수가 없어지게 됩니다. 그렇기 때문에 14번째 줄의 static을 빼고 컴파일 하게되면 전부 1번째라는 말이 나옵니다. 하지만 함수를 종료하는 시점에서도 값을 유지하기 위해 static을 넣어주게 되면 값이 계속 유지되면서 출력되게 됩니다. 또 전역변수로 선언하게 되면 이 함수 이외에 다른 함수에서도 이용할 수 있기때문에 함수의 독립성을 보장하여 주지 못합니다. 정적 변수를 잘 활용하게되면 구조적으로 좋으며 디버깅에 유리한 코드를 작성이 가능합니다.
'Programming > C' 카테고리의 다른 글
C언어 - 표준 함수 (0) | 2015.08.11 |
---|---|
기억 부류(Storage Class) (2/2) (0) | 2015.08.10 |
C언어 - 함수(function)(4/4) (0) | 2015.08.07 |
C언어 - 함수(function)(3/4) (0) | 2015.08.05 |
C언어 - 함수(function)(2/4) (0) | 2015.07.31 |