언어 자료구조 알고리즘/C 언어 문법

9. 변수의 종류

언제나휴일 2009. 8. 19. 05:47
반응형
변수의 종류

 

다루는 내용

   - 전역 변수

   - 지역 변수

   - static, extern, const  

   - Storage Class

 

1. 전역 변수 vs 지역 변수, 그리고 static, extern, const

 프로그램에서 관리해야 할 데이터를 위해 변수를 선언을 하는 것은 모두 알고 있을 것이다.

 

변수 선언의 위치

지역변수 특정 블록 내에 선언
전역변수 특정 블록 내가 아닌 블록 외부에 선언

 

 전역 변수는 변수 선언의 위치가 특정 블록내에 선언되어 있지 않고 블록 외부에 선언된 변수를 얘기를 한다.  그리고, 특정 블록내에 선언된 변수를 지역 변수라 한다.

 

 

가시성

static이 붙은 전역 변수 선언된 소스 파일에서만
static이 붙지 않은 전역 변수 extern으로 명시하면 모든 소스파일
지역변수 선언된 블록 내

 

 변수의 선언부가 특정 블록 내에 선언을 하면 가시성이 해당 블록에만 존재하게 된다.  특정 블록에 속하지 않는 변수의 경우는 static 예약어를 사용함으로써 선언된 소스파일에 있는 함수에서만 가시성이 존재하게 할 수도 있고 static예약어를 붙지 않는 경우에 extern으로 명시함으로써 다른 소스파일에서도 접근할 수 있게 된다. 

 

메모리 할당
전역 변수 프로그램 시작 시 할당, 종료 시 해제
static이 붙은 변수 프로그램 시작 시 할당, 종료 시 해제
static이 붙지 않은 지역변수 블록 시작 시 할당, 블록 종료 시 해제

 

 변수를 선언하면 변수의 형식의 사이즈만큼 메모리가 할당이 되는데 특정 블록에 속하지 않는 변수의 경우는 프로그램 시작할 때 할당되고 프로그램 종료할 때 해제된다.  또한, 블록 내부에 선언되어 있는 경우에도 static 변수의 경우는 마찬가지이다.  그 외에 블록내에 선언된 변수의 경우는 해당 블록이 수행시작될 때 할당되고 수행이 끝날 때 해제된다.  참고로 함수의 입력 매개변수는 함수 블록 내에 있는 것으로 간주한다.

 

그리고, 데이터를 위해 메모리를 할당하면서 값을 초기화를 한 후에 변경을 하지 못하게 상수화 변수를 선언하고 싶을 경우에는 const예약어를 사용하면 된다.  const 예약어를 사용하면 #define을 이용해 정의한 상수의 경우와 달리 메모리가 할당됨으로써 디버깅 시에 해당 메모리의 값을 확인할 수가 있는 편의성이 있다.

 

주의할 것

static 예약어가 붙은 변수는 extern으로 명시할 수 없다.
const가 변수 선언문에는 반드시 초기화를 해야 한다.
extern은 명시문으로 초기화를 할 수 없다.

 

 

가시성

 특정 블록내에 변수명의 가시성이 해당 블록에만 있다고 하였다.  이는 해당 변수를 위해 할당한 메모리에 대한 접근을 해당 블록에서만 할 수 있다는 얘기는 결코 아니다.  블록 내에 있는 변수는 해당 블록이 시작될 때 할당이 되고 해당 블록이 끝날 때 해제된다고 하였는데 해당 블록에서 호출하는 함수의 입력 매개 변수로 지역 변수의 주소를 넘겨 줌으로써 피 호출 함수에서 해당 메모리에 접근할 수 있게 된다.

 

 

신뢰성

 이 책에서는 신뢰성을 위해 const가 붙지 않은 전역 변수의 경우는 모두 static예약어를 붙여서 해당 소스파일에서만 가시성이 존재하게 할 것이다.  대신 다른 소스파일에서 정당하게 접근해야 할 경우를 위해 함수를 통해 해당 변수에 접근하여 값을 참조하거나 갱신할 수 있게 할 것이다.

 

 예를 들어, 회원 관리 프로그램에서 전체 회원의 로긴, 로그 아웃, 로긴 된 회원 수를 관리하기 위해 logcnt라는 변수를 전역 변수로 두었고 static예약어를 사용하지 않았다고 가정하자.  이럴 경우에 다른 소스파일에서 해당 변수명에 대한 가시성이 생겨 잘못 사용을 할 수도 있을 것이다.  이럴 때 책임을 잘못 사용한 이에게 묻는 것이 정당한가?  사견을 밝힌다면 logcnt라는 변수에 static으로 명시하지 않은 이의 책임을 묻는 것이 옳다고 생각한다.

 

 

 

 1. static을 extern으로 명시하여 참조하지 못한다.

 

 #ifndef __B_H
#define __B_H
#include "ehlib.h"

#define MAX_STU  50

extern int logcnt;
extern const int max_stu;
extern int Login();
extern int Logout();
extern int LogCnt();
#endif

 #include "b.h"

const int max_stu = MAX_STU;

static int logcnt;

int Login()
{
     logcnt++;
     return logcnt;
}

int Logout()
{
     logcnt--;
     return logcnt;
}

int LogCnt()
{
     return logcnt;
}

 #ifndef __DEMO_H
#define __DEMO_H

#include "b.h"

#endif

 #include "Demo.h"

int main()
{
     logcnt++;
     return 0;
}

 

 

 2. 적절히 사용한 예

 #ifndef __B_H
#define __B_H
#include "ehlib.h"

#define MAX_STU  50

//extern int logcnt;
extern const int max_stu;
extern int Login();
extern int Logout();
extern int LogCnt();
#endif

 #include "b.h"

const int max_stu = MAX_STU;

static int logcnt;

int Login()
{
     logcnt++;
     return logcnt;
}

int Logout()
{
     logcnt--;
     return logcnt;
}

int LogCnt()
{
     return logcnt;
}

 #ifndef __DEMO_H
#define __DEMO_H

#include "b.h"

#endif

 #include "Demo.h"

int main()
{

    //...to be defined...
    Login();

    //...to be defined...
    return 0;
}

 

 

 

2. Storage Class

 변수의 Storage Class란 할당되는 메모리가 CPU에 있는 레지스터인가 아닌가에 대한 구별이다.  setjump, longjump를 사용하여 고전적인 예외처리를 할 경우 setjump시에 CPU에 있는 레지스터 정보를 보관하고 longjump시에 보관되었던 레지스터 정보를 다시 로드를 한다.  이 경우에 CPU에 할당된 레지스터 변수는 longjump에 의해 보관되었던 값으로 복원 됨으로써 setjump호출에서 longjump호출 사이에 변경했던 것이 무효화 될 수 있다.  이러한 측면에서 바로보는 것이 Storage Class인데 이 책의 집필 목적이 OOP를 학습하기 전에 C언어를 학습하는 이들을 위한 것이라 벗어난 내용이라 생각이 된다.  확인하고자 하는 이는 Unix System Programming을 참고하기 바란다.

 

Storage Class 맛만 보기

register 예약어가 붙는 변수는 우선적으로 CPU내의 레지스터에 할당된다.  하지만 레지스터의 수가 한정되어 있어 모든 것을 register예약어를 붙인다면 보장할 수 없을 것이다.  즉, register예약어를 붙이면 우선적으로 CPU내의 레지스터에 할당되지만 보장할 수는 없다.

 

auto 예약어가 붙으면(아무런 예약어가 없으면 auto이다.) 여유가 있으면 CPU내의 레지스터에 할당이 되고 그렇지 않으면 CPU내의 레지스터에 할당되지 않는다.  즉, auto예약어를 붙이면 register예약어가 붙은 변수들이 할당되고 나서 남은 CPU내의 레지스터에 할당될 개연성도 있다.

 

volatile 예약어가 붙으면 여유가 있어도 CPU내의 레지스터에 할당하지 않는다. 

 

반응형