일단 기초적인 내용부터 파악해보자.
아래 코드는 C에서 가장 기초적인 static개념을 설명해줄 수 있는 코드이다.
#include
void fct (void);
int main(void)
{
int i;
for(i=0;i<5;i++)
{
fct();
}
return 0;
}
void fct(void)
{
static int val1 = 0;
int val2 = 0;
val1++;
val2++;
printf("Static val = %d\n", val1);
printf("NOT Static val = %d\n\n", val2);
}
Result:
Static val = 1
NOT Static val = 1
Static val = 2
NOT Static val = 1
Static val = 3
NOT Static val = 1
Static val = 4
NOT Static val = 1
Static val = 5
NOT Static val = 1 |
보다시피 static으로 선언된 값은 함수 호출시마다 val 값이 1식 증가하는데 반해
그냥 선언된 변수는 함수가 종료되면서 메모리상에서 사라짐에 따라 출력결과는 계속 1이 된다.
함수 내에 선언된
static 변수는 그 특성이 전역 변수와 비슷하다. 전역 변수는 메모리 공간을 할당받고 초기화가 이뤄지면
프로그램이 종료될 때까지 소멸되지도 않고 초기화도 두 번 다시 일어나지 않는다. static변수도 마찬가지이다.
비록 함수 내에 선언되어 있음에도 불구하고 그 특징은 전역 변수에 가깝다.
지역 내에서만 접근을 허용한다는 지역 변수의 특징을 제외하면 오히려 전역변수에 가깝다.
17번째 줄의 처음 호출시 static 변수 val1은 메모리공간을 할당받으며 0으로 초기화된다.
그러나
두번째 호출 시에는 17번째 줄은 완전히 무시되어 버린다. static변수는 한번만 초기화된다! 마치 전역변수처럼 말이다.
이 내용이 c에서 static변수의 기본적인 내용이다.
-------------------------------------------------------------------------------------------------------------------------
MAR/28/10 updated
extern 과 static 이 함수에 사용될때와 변수에 사용될때에 따라 구분해보자.
하나의 프로그램을 개발할때 하나의 파일만으로 개발하는것이 아니라, 여러사람이 여러개의
파일을 이용해서 개발할것이다. 즉, 여러파일로 개발을 하고 나중에 통합할때 이용될수 있겠다.
=== 함수일때
1. 함수에 사용될때 extern을 사용하면 다른 함수에서 해당 함수를 호출할수 있다. 이것은 디폴트 방식이기도 하다(아무것도 써주지않을때 기본적으로 extern 이다.) . 함수를 작성할때 extern 을 써주지 않아도, 다른 파일에서 해당 함수를 호출
할수 있는방식이다. 즉, extern 지정은 함수가 정의된 화일외에 다른 화일에서 함수의 호출을 허용한다.
2. static 지정을 하면 함수가 정의된 파일에서만 이 함수를 호출할수 있다. 즉 다른파일에서는
이 함수를 호출할수 없는것이다. 즉 여러파일에 같은 함수 이름이 존재한다고 해도 에러를 발생시키지 않는다는것이다.
=== 변수일때
3. 외부변수 (extern)는 함수밖에서 선언되어 선언된 시점이후 모든 함수에서 사용가능한 변수이다.
외부변수의 선언은 각 함수간에 자료를 공유하는 경우에 사용되는 변수이다.
4. 외부변수는 함수의 밖에서 선언되어 선언된 시점이후 화일의 끝가지 모든 함수에서 사용가능하고 프로그램의 종료시 까지 메모리에 할당되어 소멸되지 않는다.
5. 여러개의 파일을 이용해서 개발할때
AAA 파일에 int erp; 라는 변수가 외부변수라 선언되어 있다면
BBB, CCC 파일에서 erp 라는 변수를 사용하고 싶다면
BBB, CCC 파일에 extern 으로 선언한다. 이렇게 하면 erp라는 변수를 참조할수 있다. 이것을
BBB, CCC 에서는 extern int erp; 라고 해서 사용한다.
외부파일을 참조한다는것을 선언하면 메모리 할당은 하지 않고, 각 화일 간에는 자료를 공유하게 된다.
또한 참조를 함수내에서 하게되면 해당 함수내에서만 사용가능하다. 물론 외부참조를 하면
해당 파일내에서 전부사용가능하다.
즉, extern 이라고 한다면 자기파일이 아닌 다른파일에 외부변수로 선언되었다는것을 알수있고,
여기서는 그것을 사용하기만 하면된다.
me) 외부변수를 많이 사용하면 부작용(side-effect)가 발생할 확률이 높고, 함수간의 독립성을
저해시킬수 있다.
6. 정적변수(static)변수에도 내부 정적변수와 외부정적변수가 있다.
내부정적변수는 함수내부에 선언되어 사용되는 변수로서 자료의 값이 소멸되지 않고, 메모리에
영구적으로 존재하는 변수이다. 함수실행후에 값이 유지되기 때문에 이전값을 알수 있고, 모듈의 독립성을 보장을 위해 사용되는 변수이다.
void sum()
{
static int sdt = 0; 처음에만 0 값이고 처음에만 초기화 되고, 다음함수에 들어올때는 초기화되지 않고 사용가능하다. 값이 유지된다.
}
7. 외부정적변수는 함수의 외부에 선언된 정적변수로서 해당 파일내에서만 사용가능하고, 전체
함수에서 사용될수 있는 변수이다. 다른파일에서는 사용불가능하다. 즉 외부 참조할수 없다.
그러므로, 다른 파일에 같은 이름이 존재하는 외부정적변수가 있더라도 서로 영향을 미치지 않는다.
B.======================================================================================
static 변수는 정적 변수하고 하고,
내부 static과 외부 static으로 나누어 집니다.
extern 변수와 static 변수는 한번 선언되어 지면
0 또는 null로 초기화 되어 있고,
그 프로그램이 끝날 때 까지 존재합니다.
내부 static 변수는
{,} (<-중괄호) 안에 선언되어 있는 static 변수이고
대부분 함수나 클래스 내에서 선언되어 있습니다.
선언되어진 그 함수나 클래스가 아닌
다른 함수에서는 사용이 불가능하다.
외부 static 변수는
함수 밖에서 선언된 static 변수입니다.
외부 static 변수는 함수 밖에서 선언되어 있지만
그 변수가 선언된 이후의 모든 함수 내부에서
접근, 사용이 가능합니다.
예)
static int a=23; // 외부 static 변수
void main()
{
printf("%d", a); // 이전에 a가 선언되었으므로 사용 가능
printf("%d", b); // 이전에 b가 선언되어 있지 않으므로 사용 불가능
sub1();
sub2();
}
void sub1()
{
static int b=45; // 내부 static 변수
printf("%d", a);
printf("%d", b);
}
void sub2()
{
printf("%d", b); // sub1에서 선언하였기 때문에 사용할 수 없다.
}
단,
void sub1()
{
static int a=3;
void sub2()
{
printf("%d", a); // 접근, 출력 가능
}
}
이런 경우는 sub1에서 선언되어 있지만
sub2는 sub1에 포함되어 있기 때문에
sub2에서도 a를 사용할 수 있다.
extern 변수는 외부 변수로
어떠한 static 변수가 선언되어 있지만
그 프로그램 전체의 파일이 한개가 아니고 여러개인 경우
사용된다.
만약 파일이 a.c와 b.c로 나뉘어져 있지만
전역변수를 a.c에서 선언하고 b.c에서 또 선언하면
나중에 link할 때 같은 변수를 여러번 선언했다고 오류가 난다.
이럴 때 extern 변수를 사용한다.
예)
// file a.c
int temp=12; // extern 변수 선언 - 실제로 메모리가 할당되는 부분은 이곳이다. temp는 static으로 선언한 것과 동일하다.
void main()
{
printf("%d", temp);
sub();
}
// file b.c
extern int temp; // 실제로 메모리가 할당되는 것이 아니고 함께 link되는 파일 중에 temp가 선언되어 있다고 표시만 하는 것이다.
void sub()
{
printf("%d", temp);
}
C.======================================================================================
지역 변수
지역 변수란 어떤 한정되 지역 에서만 사용할수 있는 변수를 말합니다.
블럭 안에서 선언된 변수는 모두 지역 변수이고, 이때 이 블럭이라는
한정된 지역에서만 이 변수를 사용할수 있습니다.
그리고 지역 변수는 그 변수가 선언된 블럭이 끝나면
그 변수에 들어있는 값을 잃게 됨니다.
참고로 지역 변수를 선언할때는 블럭의 윗부분에 선언을 해야 합니다.
모든 작업 전에 선언해야 하죠. 그렇지 않으면 에러가 납니다.
예제 소스 하나를 보도록 하죠.
/* 파일 이름 : C4-1.C
프로그램 내용 : 지역 변수를 설명하는 프로그램. */
void main()
{
int a;
{
int b;
a=5;
b=10;
}
a=10;
}
이 소스는 지역 변수를 설명하기 위한 간단한 소스 입니다.
우선 a라는 변수는 main함수의 블럭 안에 있으므로 지역 변수가 됨니다.
그러므로 main함수의 블럭 안에서만 사용 가능하죠.
그리고 main함수 안에는 또 블럭이 있습니다.
그리고 그 블럭 안에는 변수 b가 선언 되어 있는데
이것두 블럭 안에 있으므로 지역 변수가 되죠 또한 이거 역시 그 블럭 안에서만
사용할수 있습니다.
그런데 그 블럭에서 변수 a에 5를 대입하고 있는데
a는 이 블럭 밖에 선언되어 있죠..?
이렇게 블럭 밖에 있는 변수에 대해서는
모두 사용이 가능합니다.
전역 변수
전역 변수는 지역 변수와는 다르게 한정된 지역이 아닌 모든 지역에서
사용이 가능한 변수를 말하는 것 입니다.
블럭 밖에서 선언된 변수는 모두 전역 변수 이죠.
그리고 전역 변수는 프로그램이 끝날때까지 들어있는 값을
계속 유지합니다.
그럼 예제 소스를
/* 파일 이름 : C4-2.C
프로그램 내용 : 전역 변수를 설명하는 프로그램. */
int a;
void func()
{
a=5;
}
void main()
{
func();
a=10;
}
이 소스에서 모든 블럭 밖에 a라는 변수가 선언되어 있으므로
a는 전역 변수 입니다.
그러므로 어느 곳에서든지 사용이 가능하죠
소스에소 볼수 있는것 처럼 a라는 변수는 main함수와 func라는 함수에서
모두 사용할수 있습니다.
그러면 에제 하나를 더 볼까요?
/* 파일 이름 : C4-3.C 프로그램 내용 : 전역 변수를 설명하는 프로그램. */
void func() { a=5; }
int a;
void main() { func(); a=10; }
이 소스는 위에 것과 똑같지만 전역 변수 선언을
func함수와 main함수 사이에 한 것 입니다.
전역 변수를 쓰려면 그 변수가 그것을 쓰는 부분의 위쪽에
선언되어 있어야 합니다.
func함수 안에서 a를 사용하고 있는데 a는 그 아래에 선언되어 있죠?
이럴땐 func함수 위에 a라는 전역 변수가 있다는 것을 알려주면 됨니다.
방법은 간단한데
extern 데이터형 변수명;
이렇게 해 주면 됨니다.
아까 그 소스를 고쳐보면
/* 파일 이름 : C4-4.C
프로그램 내용 : 전역 변수를 설명하는 프로그램. */
extern int a;
void func()
{
a=5;
}
int a;
void main()
{
func();
a=10;
}
이렇게 해 주면 간단히 해결 되죠 하지만 특별한 경우가 아니라면
a라는 변수 선언을 위에 해 주는 것이 좋겠죠?
정적 변수
정적 변수에는 크게 두가지로 나눌수 있는데 정적 지역 변수와
정적 전역 변수 입니다.
(1) 정적 지역 변수
지역변수를 배울때 지역변수는 그 변수가 선언된 블럭이 끝나면
그 변수안에 들어있는 값을 잃는다고 했습니다.
그런데 이걸 잃게 하지 않을때 쓰는 것이 정적 지역 변수 입니다.
정적 지역 변수는 지역 변수 선언 앞에 static키워드만 붙여 주면 됨니다.
예를 들어
static int a;
이런 식으로 이렇게 해주면 이 변수가 선언된 블럭이 끝나도
그 안에 들어있는 값을 잃지 않죠.
/* 파일 이름 : C4-5.C
프로그램 내용 : 정적 지역 변수를 설명하는 프로그램. */
#include <stdio.h>
void func()
{
int a=0;
a=a+1;
printf("%d\n",a);
}
void main()
{
func();
func();
func();
}
이 프로그램의 실행 결과는 어떻게 될까요?
C:\>C4-5.EXE
1
1
1
C:\>
이렇게 나옴니다. 왜 그런줄은 다 아실꺼에요.
그런데 여기서 func함수 내의 a변수를 정적 변수로 선언하면
/* 파일 이름 : C4-6.C
프로그램 내용 : 정적 지역 변수를 설명하는 프로그램. */
#include <stdio.h>
void func()
{
static int a=0;
a=a+1;
printf("%d\n",a);
}
void main()
{
func();
func();
func();
}
이렇게
그러면 결과는 어떻게 바꿜까요????
a라는 변수는 func함수가 끝나도 그 안의 값이 보관 되므로
C:\>C4-6.EXE
1
2
3
C:\>
이런 결과가 나오겠죠?
이제 정적 지역 변수에 대해서는 이해가 되셨죠??
(2) 정적 전역 변수
정적 전역 변수를 하기 전에 한가지 의문정이 생기실 겁니다.
변수는 프로그램이 끝날때까지 그 값이 유지되는데
정적 전역 변수라는게 왜 따로 있을까요???
사실 정적 전역 변수와 정적 지역 변수의 의미는 크게 다름니다.
static키워드를 붙여 전역 변수를 선언하면
즉 정적 전역 변수를 선언하면
외부 소스에서 이 변수를 엑세스 할수 없게 되죠
그게 정적 전역 변수의 주 목적 입니다.