기억부류

  • 기억 부류 : Storage Class)
    변수가 저장되는 위치에 따라 결정되는 변수의 여러가지 성질
    크게 4가지로 구분


 기억부류

 전역

 지역

 정적

 레지스터

 지정자

 extern

 auto

 static

 register

 지정 장소

 정적 데이터 영역

 스택

 정적 데이터 영역

 CPU의 레지스터

 선언 위치

 함수의 외부

 함수의 내부

 함수의 내부

 함수의 내부

 통용 범위

 프로그램 전체

 함수의 내부

 함수의 내부

 함수의 내부

 파괴 시기

 프로그램 종료시

 함수 종료시

 프로그램 종료시

 함수 종료시

 초기값

 0으로 초기화

 초기화되지 않음

 0으로 초기화

 초기화되지 않음


  • 기억부류에서 가장 중요하는 것은 전역변수와 지역변수를 구분하는 것이다.


지역변수와 전역변수

  • 변수의 선언 위치가 다르다.
    전역 변수는 함수 바깥쪽에서 선언하고 지역 변수는 함수 내부에서 선언 한다.

  • 통용 범위 또한 다르다. 통용범위란 변수가 사용될 수 있는 범위
    전역 변수는 특정 함수 내에 선언 된 것이 아니라 함수에 속하지 않고 프로그램 전체에서 사용
    지역 변수는 자신이 선언된 함수에 소속되어 있기 때문에 함수 외부에서는 변수 사용이 불가하다
    자신의 임수를 수행하기 위해서 잠씨 쓰고 버리는 것. 

  • 변수의 파괴 시기가 다르다. 변수는 값을 기억하기 위해 메모리를 할당받아 사용
    사용 이후에 변수가 파괴되는데 변수를 파괴한다는 것은 곧 메모리의 회수를 의미
    지역변수는 특정 함수 내부에서만 사용 : 함수가 실행 중일 때만 메모리를 차지하며 함수가 끝나면 변수의 생명도 끝나고 사라진다. ( 함수와 함께 운명을 같이 한다.)
    전역변수는 프로그램에 소속되어 있고 모든 함수에서 사용 가능해야 하므로 프로그램 실행중인 동안에는 파괴 되지 않는다. ( 프로그램과 운명을 같이 한다. )

  • 변수가 생성되는 기억 장소가 다르다 
    전역 변수는 한 번 정해진 위치에 계속 남아 있어야 하므로 정적 데이터 영역에 생성
     - 정적 데이터 영역이란 프로그램의 코드 바로 다음에 위치하는 실행 파일의 한 부분
    지역 변수는 프로그램 실행 중에 생성, 파괴를 반복 하므로 스택(데이터의 임시 저장소)에 생성
     - 프로그램은 실행에 필요한 임시적인 정보들을 스택에 차곡차곡 저장한다. 

  • 초기화 여부가 다르다.
    전역 변수는 별도의 초기식이 없더라도 0으로 초기화 해준다.
    전역 변수는 컴파일될 때 컴파일러에 의해 초기화된 채로 실행 파일에 새겨지므로 초기화 시간은 0
    지역 변수는 초기식이 없을 경우 초기화되지 않는다. 이 때에는 무슨 값인지 알 수 없는 쓰레기값(Garbage) 라고 한다. 초기식이 없을 때 초기화 하지 않는 이유는 함수가 호출 될 때마다 변수가 새로 생성되기 때문에 매번 변수를 초기화 하자면 그만큼 실행 속도가 느려지므로 안한다.



  • 지역 변수의 장점
    1. 함수의 독립성 향상 : 프로그램은 함수로 구성 함수는 프로그램의 부품
    재활용을 높이기 위해 부품끼리 공유하는 것(전역변수)이 많다보면 의존 관계를 가지게 되므로 좋지 않은 구조를 만들어 낸다. 지역 변수는 함수가 자신이 필요로 하는 모든 정보를 가질 수 있도록 (Self Contained) 해주므로 독립성을 높여 준다.
    2. 디버깅 효율을 향상 : 버그, 즉 논리적인 에러가 발생하는 원인의 십중팔구는 변수의 조작 미스!!
     전역 변수가 편하다고 남발하다 보면 디버깅 시에 살펴 봐야할 변수의 수가 증가!! 
     작은 프로그램의 경우 크게 상관은 없지만 큰 프로그램을 만들다 보면 변수가 수백개이면 지역변수의 경우 그 해당 함수만 보면 되지만 전역 변수의 경우 모든 곳을 다 돌아 봐야하는데 시간이 오래 걸리기 때문이다!!!
    3. 메모리의 절약 : 전역 변수는 프로그램 실행 시 생성 되어 계속 값을 유지하므로 그만큼 메모리를 항상 차지하게 된다. 지역 변수는 함수가 호출될 때만 생성되며 함수가 종료되면 즉시 파괴되므로 자신이 속해 있는 함수가 실행중일 때만 메모리를 차지한다. 
    4. 재귀 호출이나 상호 호출같은 특별한 기법은 지역 변수가 있어야 사용. 함수가 호출될 때마다 새로은 변수가 생성되어야만 가능한 기법이다.

  • 외부변수 : 변수의 확장형
    [지정자]타입 변수명;

    지정자(Specifier)는 기억 부류를 비롯하여 상수 지정, 최적화 금지 등 변수의 여러 가지 성질을 지정하는 키워드인데 필요가 없을 경우 생략가능
    기억부류 지정 키워드 : auto, extern, static, register
    - auto : 지역변수 선언시 변수의 타입 앞에 auto 키워드를 붙인다.
            함수 내부 : auto로 인식하여 지역변수
            함수 외부 : 전역변수로 선언

    - extern : 정보가 공개된 이후에만 사용이 가능한데 이러한 선언을 하는 키워드
        함수에서 전역 변수를 사용하기 위해 extern 선언이 원칙적이지만
        다음 규칙이 만족할 경우 extern의 생략이 가능
          - 함수보다 앞 쪽에 선언되어 있는 외부변수는 extern 선언을 하지 않아도 된다.
          - 변수 선언문이 더 앞쪽에 있다면 상관이 없지만 뒤 쪽에 있을 경우 extern 선언이 필요!
          - 외부 모듈에 있는 전역 변수를 참조하고자 할 때 소스의 선두에 extern 선언!!!!!!!!


정적변수

  • 전역변수와 지역변수의 성격을 동시에 가지는 특별한 기억 부류
    위의 도표에 있는 특징을 살펴 보자
    1. 선언 위치 : 함수의 내부(지역변수)
    2, 통용 범위 : 함수의 내부(지역변수)
    3. 저장 장소 : 정적데이터영역(전역변수)
    4. 프로그램 실행 중에 항상 존재
    5. 초기값 지정이 없으면 0으로 초기화되고 프로그램 실행시 단 한번면 초기화!!!!
    정적변수 지정자 : static

  • 정적 변수는 함수 내부에서 그 안에 있는 값을 함수가 삭제되고 난 뒤에도 값을 유지하고 싶을 경우에 사용하게 된다. 따라서 다른 프로젝트로 가져가도 사용이 쉽워 재사용성이 높아진다.

  • 주의 사항 : 초기화가 언제되는 지를 알아야 한다.
    매번 함수를 호출할 때마다 static int blac=0; 이라는 코드를 통해 0으로 계속 초기화 한다면 
    static 을 사용하는 의미가 퇴색되게 된다. 
    전역 변수와의 가장 다른 점은 extern 선언을 통해 외부 모듈로 정보 공개가 되지 않는다. 


레지스터 변수

  • 레지스터 변수의 특이점으로 지역, 전역, 정적 변수들은 정적 데이터 영역이든 스택이든 메모리의 한 구석에 생성 되지만 레지스터형 변수는 CPU의 레지스터에 저장된다.
    레지스터(Register)란 CPU의 구성 부품 중 하나 이며 CPU가 데이터를 처리하기 위해 사용하는 임시 작업장이라 할 수 있다. 
    컴퓨터의 가장 핵심 부분인 CPU의 한가운데에 있는 기억 장소이기 때문에 레지스터의 속도는 메모리 보다 훨씬 빠르다 읽고 쓰는 속도는 수십억분의 1초 정도 밖에 걸리지 않는다. 
    CPU의 종류에 따라 다르지만 레지스터에 따라 다르지만 레지스터는 보통 10개~20개 정도밖에 없는 아주 귀한 기억 장소인데 여기에 변수를 저장하면 이 변수를 참조하는 문장의 속도가 빨라진다.



  • 레지스터의 크기는 CPU의 비트수를 결정하는 중요한 기준인데 레지스터가 32비트면 32비트 CPU라고 부른다. 대부분 CPU는 32비트이므로 레지스터들도 전부 32비트 이고 따라서 저장 가능한 변수의 타입은 int, unsigned, 포인터 형 등의 32비트형, double 같은 실수형은 저장할 수 없으며 구조체나 배열은 안된다. 에러는 아니지만 지정해 봐야 무시당한다.
    레지스터의 개수가 많지 않기 때문에 레지스터형 변수두 개까지만 선언이 가능하다.

  • 한정된 자원이기 때문에 일시적으로 사용할 지역변수에만 지정할 수 있으며 전역변수는 지정이 불가능 하다. 프로그램과 생명을 같이 하는 전역변수가 레지스터 하나를 차지한다면 프로그램 실행 중 레지스터 하나가 묶여 버리게 될 것이다.

  • 레지스터형 변수를 쓸 때와 지역 변수를 쓸 때는 속도의 차이가 많이 난다. 요즘에는 하드웨어들이 향상 되어서 크게 차이는 없다. 
    레지스터형 변수는 컴파일러에 종속적이다. 
    레지스터형 변수는 메모리 생성이 아니므로 &연산자는 불가능하다 즉, 이 변수로 메모리의 주소를 조사할 순 없다. 하지만 레지스터형 포인터 변수가 번지를 기억할 수 있으므로 *연산자를 사용하는 것이 가능하다. 

  • 레지스터형 변수와 지역변수는 근소한 속도 차이외에는 아무 차이가 없으므로 컴파일러가 사용자의 지시를 무시하고 기억 부류를 바꾸어도 별 문제가 없다.


정적함수

  • 함수도 기억 부류를 가진다. 함수는 전역이니 지역이니 하는 개념은 존재 하지 않으며 레지스터형 기억 부류도 당연히 없다.
    C의 함수는 수평 적인 평등 관계며 어떤 함수를 다른 함수의 지역 함수를 허용하지 않으므로 C의 함수들은 원칙적으로 전역이다.

  • 함수에 적용 되는 것은 정적(static) 기억부류 밖에 없다. 정적 함수는 특정 모듈에서만 사용할 수 있으며 외부 정적변수의 특성과 유사. 함수의 정의문에 static이라는 지정자만 붙이면 정적함수가 된다. 

  • 정적 함수와 반대되는 경우도 있는데 이름을 붙일 경우 외부함수나 비정적 함수가 될 것이다. 외부 함수는 별다른 지정 없이 항상 외부로 알려지며 원형 선언만 하면 어떤 모듈에서나 이 함수를 호출 할 수 있다.

  • 정적 함수는 특정 모듈에서만 사용하도록 정의된 것이므로 외부에서 원형을 선언한다 하더라도 함수의 호출이 불가능 하다. 이유는 정적 변수의 경우와 같이 이름 충돌을 방지하기 위해서 이다. 재사용을 위해서 모듈에서 ReadFile이라는 함수를 사용하는데 이름이 너무 일반 적이여서 프로젝트 내에서 충돌할거 같은 경우 static 으로 선언하면 된다. 




  • 위의 경우 모듈을 프로젝트 내에 모두 포함 할 경우 Comp, Decomp 함수를 이중으로 정의 하는 형태가 되어 제대로 컴파일이 되지 않는다. 

  • ZIP과 Network는 개별적으로 원할 때만 포함시킬 수 있고 Network가 ZIP에 종속적이지 않으며 둘 다 포함하더라도 아무문제가 없어야한다. 
    이 경우의 해법이 바로 정적함수 이다.

  • 상용 라이프러리의 경우 주의사항이 늘어나 고객들이 좋아 하지 않고 가격 정책을 결정하는데도 문제가 된다. 만약 Network 가 ZIP 보다 비싼 모듈인데 Network를 사면 ZIP도 끼워서 팔아야 하는 문제가 생긴다. 정적함수는 같은 코드가 중복되는 문제점이 있지만 충돌이 발생하는 것보다 낫기 때문에 제공 되는 것이다.



통용범위

  • 규칙 : 
    변수나 함수, 태그 같은 명칭은 상호 구분되어야 하므로 중복이 불가능.
    그 예외의 사례가 있는데 통용 범위가 다른 명칭끼리는 같은 이름을 가질 수 있다.
    즉, 다른 함수에서 같은 이름의 변수명 즉, 지역변수로 선언하게 되면 크게 문제가 없다.

  • 문제가 되는 경우는 전역변수로 선언한 int i 와 main함수 안에 전역변수 i를 사용하고 func함수에서는 지역변수 int i를 선언 하게 되면 일반적으로 모호함이 발생하지만 컴파일러에서 좁은 범위를 가지는 명칭 즉, 지역변수 i에게 우선권을 주게 된다. 전역 변수 i 는 사용할 수가 없게 된다.
    사용하기 위해선 ::i 라는 형태로 사용하면 전역 변수를 사용 할 수 있다.

  • 블록 범위 :
    지역 변수는 { } 괄호안의 블록에 선언된 블로 내부에서만 통용되고 { } 괄호 안에서만 통용된 범위를 블록 범위라 한다. 일반적으로 { }는 함수의 시작과 끝을 나타내기 떄문에 지역변수의 통용 범위는 함수 내부가 되는 것.

  • 선언과 정의

     기억부류

     전역

     지역

     정적

     레지스터

     지정자

     extern

     auto

     static

     register

     지정 장소

     정적 데이터 영역

     스택

     정적 데이터 영역

     CPU의 레지스터



함수의 설계 원칙

  1. 함수의 이름은 최대한 설명적으로 작성하여야 한다. 
    이름만으로 무엇을 하는지 어떻게 쓰는 것인지도 알 수 있도록 한다.
    기능을 명확히 아는 것 < 동사, 목적어, 약간의 수식어로 구성 >

  2. 두 번 이상 반복된 코드는 반드시 함수로 분리한다.
    똑같은 코드를 중복된 채로 내며려 두면 커진다. 10줄 자리 코드를 10번 반복한다면 나머지 90번의 코드는 불필요하게 된다. 코드의 유지와 확정성이 곤란해진다.
    위와 같은 경우 수정할 것이 있으면 일일히 다 해야 되지만 함수로 해둘 경우 함수의 내부만 수정해 주면 된다. 실수로라도 빼먹게 되면 버그의 온상지가 되어버린다.

  3. 반복되지 않더라도 한단위로 볼 수 있는 작업은 함수로 만든다.
    배열의 초기화나 단순한 메뉴형태를 출력하는 경우도 함수로 만들는 것이 좋다.
    한 함수으 소스가 길어지면 작업 파악에 많은 시간이 소요된다.

  4. 한 함수는 한가지의 기능만 수행해야 한다. 
    위에서 말했듯이 프로그램을 구성하는 부품이며 부품은 전체를 구성하는 원자적인 단위이고 재사용성 향상을 위해서 한가지의 기능만 수행하는 함수를 만들어야 한다.

  5. 입력과 출력이 직관적이고 명확 해야 한다.
    인수는 함수에게 주어지는 작업거리인데 함수가 하는 일에 꼭 필요한 정보만 최소한의 인수로 받아 들여야한다. 

  6. 함수는 자체적으로 에러를 처리해야 한다. 
    함수는 독립된 작업을 하며 재사용가능한 부품이므로 그 자체로 완벽하게 동작할 수 있어야 한다.
    모든 경우의 수를 따져서 에러처리를 해야한다. 이 경우 어떠한 프로젝트에 가져가도 별도의 수정 없이 재사용이 가능한 부품이다. 

위 6가지 원칙이 참고사항일 뿐이지 필수는 아니다. 하지만 참고사항을 유념해두고 연습과 분석이 필요하다.

기억부류는 4가지로 구분한다

지역 변수, 전역 변수, 정적(static) 변수, 레지스터(Register)변수

통용범위와 함수의 6가지 원칙에 대해 알아보았다.

출처 : soen.kr



'언어 > C' 카테고리의 다른 글

배열  (0) 2016.03.25
표준함수  (0) 2016.03.19
함수와 프로시저  (0) 2016.03.18
연산자  (0) 2016.03.14
제어문  (0) 2016.03.13

+ Recent posts