7.1 지역변수
7.1.1 전역변수와 지역변수
-
기억 부류(Storage Class)
변수가 저장되는 위치에 따라 결정되는 변수의 여러 가지 성질을 의미
변수가 어디에 생성되는가에 따라 통용 범위와 파괴 시기 등의 특징이 결정
기억 부류 |
전역 |
지역 |
정적 |
레지스터 |
지정자 |
extern |
auto |
static |
register |
저장 장소 |
정적 데이터 영역 |
스택 |
정적 데이터 영역 |
CPU의 레지스터 |
선언 위치 |
함수의 외부 |
함수의 내부 |
함수의 내부 |
함수의 내부 |
통용 범위 |
프로그램 전체 |
함수의 내부 |
함수의 내부 |
함수의 내부 |
파괴 시기 |
프로그램 종료시 |
함수 종료시 |
프로그램 종료시 |
함수 종료시 |
초기값 |
0으로 초기화 |
초기화되지 않음 |
0으로 초기화 |
초기화되지 않음 |
- 예제 Storage
#include <stdio.h> void func();
int global; //< 함수 외부에서 선언되었으므로 전역변수
void main() { int local; //< main 함수의 지역변수
global=1; //< 가능 local=2; //< 가능 //i=3; //< 불가능 }
void func() { int i; //< func 함수의 지역변수
global=1; //< 가능 //local=2; //< 불가능 i=3; //< 가능 } |
-
변수의 선언 위치가 다르다.
전역변수는 함수 바깥에서 선언
지역변수는 함수 내부에서 선언
-
변수의 통용 범위가 다르다.
전역변수는 프로그램 전체가 공유
지역변수는 자신이 선언된 함수 외부에서는 사용 안됨.
-
변수의 파괴 시기가 다르다.
변수를 파괴한다는 것은 이 변수가 차지하고 있던 메모리를 회수한다는 뜻
전역변수는 프로그램이 종료되면 파괴
지역변수는 함수의 임무를 위해 생성되었다 함수가 종료되면 파괴
-
변수가 생성되는 기억 장소가 다르다.
전역변수는 한 번 정해진 메모리 위치에 계속 남아 있어야 하므로 정적 데이터 영역에 생성
지역변수는 프로그램 실행 중에 생성, 파괴를 반복하므로 스택(데이터의 임시 장소)에 생성
-
초기화 여부가 다르다.
전역변수는 별도의 초기식이 없더라도 0으로 초기화
지역변수는 별도의 초기식이 없을 경우 초기화가 안 된다.
- 예제 LocalGlobal
#include <stdio.h>
int global;
void main() { int local;
printf("global is %d, local is %d\n", global, local); } |
위 예제를 컴파일 하면 local variable 'local' used without having been initialized 이런 경고 메세지가 출력된다.
"지역변수 local을 초기화하지 않고 사용했다"라는 뜻
7.1.2 지역변수의 장점
-
함수의 독립성을 높인다.
부품은 불가피한 경우를 제외하고는 가급적이면 스스로 작동할 수 있도록 만들어야 재활용하기 좋다.
공유하는 것(전역변수)이 많아지면 의존 관계를 가지게 되므로 서로 얼키고 설켜서 좋지 않은 구조를 만들어 낸다.
부품간의 정보 교환은 반드시 필요할 것인데 이럴 경우 리턴값을 사용하는 것이 정석이다.
-
지역변수는 디버깅 효율을 향상시킨다.
버그, 즉 논리적인 에러가 발생하는 원인의 십중팔구는 변수를 잘못 조작한 것이다.
전역변수를 많이 쓰면 전역변수의 수가 상대적으로 줄어들게 되므로 관찰 대상 범위가 대폭 좁아진다.
지역변수는 말썽을 부려봐야 자신이 소속된 함수 안에서만 유효하므로 뛰어봤자 벼룩이다.
-
지역변수는 메모리를 절약한다.
전역변수는 프로그램이 실행될 때 같이 생성되며, 계속 값을 유지해야 하므로 그만큼의 메모리를 항상 차지한다.
지역변수는 자신이 속해 있는 함수가 실행 중일 때만 메모리를 차지한다.
-
재귀 호출이나 상호 호출 같은 특별한 기법은 지역변수가 있어야만 사용할 수 있다.
함수가 호출될 때마다 새로운 변수가 생성되어야만 가능한 기법이다.
7.1.3 외부변수
지정자(Specifier)는 기억 부류를 비롯하여 상수 지정, 최적화 금지 등 변수의 여러 가지 성질을 지정하는 키워드
[지정자] 타입 변수명;
-
종류
auto, extern, static, register
-
extern
변수가 외부 어딘가에 선언되어 있다는 것을 알리는 역할로 사용
- 예제 Extern1
#include <stdio.h>
int before=11;
void main() { extern int before; extern int after;
printf("before=%d, after=%d\n",before,after); }
int after=22; |
7.2 정적변수
7.2.1 정적변수
정적변수(Static Variable)는 전역변수와 지역번수의 성격을 동시에 가진다.
특정 함수만 사용하되 그 값을 계속 유지할 필요가 있을 때 사용한다.
-
정적변수의 특징
선언 위치는 지역변수와 마찬가지로 함수의 선두이다.
통용 범위는 지역변수와 마찬가지로 함수 내부로 국한된다.
저장 장소는 전역변수가 저장되는 정적 데이터 영역이다.
정적 데이터 영역에 저장되므로 프로그램 실행 중에 항상 존재한다.
초기값 지정이 없으면 0으로 초기화되고 프로그램 실행 시 단 한 번만 초기화된다.
- 예제 Static
#include <stdio.h>
void PrintCount();
void main() { int i;
for(i=0; i<5; i++) { PrintCount(); } }
void PrintCount() { static int count=0;
count++; printf("저는 %d번째로 호출되었습니다.\n", count); } |
7.2.2 레지스터 변수
레지스터형 변수는 메모리가 아닌 CPU의 레지스터에 저장된다.
CPU의 레지스터 개수가 많지 않기 때문에 레지스터형 변수는 두개까지만 선언 할 수 있다.
비주얼 C++은 register 지정자를 완전히 무시하며 전역 최적화 옵션에 따라 자동으로 레지스터형 변수를 관리한다.
7.2.3 정적 함수
정적 함수는 특정 모듈에서만 사용할 수 있는데 앞에서 살펴본 외부 정적 변수의 특성과 유사
함수 정의문 앞에 static이라는 지정자만 붙이면 정적 함수가 됨.
이름 충돌을 방지하기 위해서 사용됨.
7.3 통용 범위
7.3.1 통용 범위 규칙
같은 함수 내에서 같은 이름을 가진 변수가 존재하면 안됨
- 예제 Scope
#include <stdio.h>
void func(); int i=3;
void main(void) { printf("i=%d\n", i); //전역변수 i를 출력 함. func(); }
void func() { int i=5;
printf("func() i=%d\n", i); } |
7.3.2 블록 범위
변수는 { } 괄호 안의 블록에 선언된 변수를 의미하여 변수가 선언된 블록 내부에서만 통용
7.3.3 선언과 정의
|
역할 |
메모리 |
정보의 완전성 |
중복 가능성 |
선언 |
알린다 |
사용 안함 |
불완전해도 됨 |
가능 |
정의 |
생성한다 |
할당 |
항상 완전해야 함 |
불가능 |
-
선언(Declaration)
컴파일러에게 대상에 대한 정보를 알린다.
함수가 어떤 인수들을 전달받으며 어떤 타입을 리턴하는지를 알리는 원형 선언
-
정의(Definition)
대상에 대한 정보로부터 대상을 만든다.
int i; 정의문에 의해 4바이트 할당, int Max(int, in) {}정의로부터 함수의 본체를 컴파일하여 코드 생성
7.3.4 설계 원칙
- 함수의 이름을 최대한 설명적으로 작성하여 이름만으로 무엇을 하는 함수인지, 어떻게 쓰는 것인지도 알수 있도록 한다.
- 두 번 이상 중복된 코드는 반드시 함수로 분리한다.
- 반복되지 않더라도 한 단위로 볼 수 있는 작업은 함수로 만든다.
- 함수는 한 번에 하나의 작업만 해야 한다.
- 입력과 출력이 직관적이고 명확해야 한다.
- 함수는 자체적으로 에러 처리를 해야 한다.