관리 메뉴

Kim's Programming

기억 부류(Storage Class) (2/2) 본문

Programming/C

기억 부류(Storage Class) (2/2)

Programmer. 2015. 8. 10. 16:26

레지스터 변수

 

레지스터형 변수는 전역변수, 지역변수, 정적변수와는 다른점이 있습니다. 이들은 메모리의 일부를 차지하여 구성이 되지만 레지스터 변수는 CPU의 레지스터에 저장이 됩니다. 레지스터(Register)이란 CPU내부의 부품 중 하나이며 CPU의 임시작업장 정도의 역할을 합니다. 컴퓨터가 작동함에 중심이 되는 CPU의 중간에 있는 부품이기떄문에 메모리 보다도 훨씬 빠릅니다. 보통 내부에 10~20개 정도 밖에 없는 공간이긴 하나 속도가 1/100,000,000(1억)초 정도도 걸리지 않습니다. 그래서 여기에 변수를 할당하게 되면 엄청난 속도로 호출 또한 엄청나게 빨라지게 됩니다. 하지만 예전과는 다르게 속도가 엄청 빨라져서 최근에는 일반적으로 하는것이나 큰 차이는 없다고 합니다.

 

정적 함수

 

기억 부류는 주로 변수에 적용이 되지만 함수도 기억부류를 가지게 됩니다. 함수에는 전역, 지역이란 것도 없고 레지스터 형도 없다. 또 다른 함수를 어떤 함수의 지역함수로 작용하게 할 수도 없습니다. 기억부류중에서는 static 기억부류만 있는데 정적 함수는 특정 모듈에서만 사용할 수 있으며 외부 정적 변수와 특성이 비슷합니다. 선언방법은 똑같이 선언하고 앞에 static만 붙여주면 됩니다.

1
2
3
4
static void function()
{
 
}
cs

외부 함수는 별다른 지정이 없는 한 외부로 항상 알려지게 되며 원형 선언만 하면 어떤 모듈에서나 이 함수를 호출할 수 있습니다. 그러나 정적 함수는 특정 모듈에서만 사용하도록 선언 한 것이기 때문에 외부에서 선언한다고 하더라도 함수를 호출할 수 없습니다. 외부에서 그 존재를 알 없도록 해야하는 이유는 외부 정적변수의 경우와 마찬가지로 충돌을 방지하기 위함입니다. 재사용을 위해 작성한 모듈에서 ReadFile이라는 함수를 사용하는데 이 이름이 너무 일반적이어서 프로젝트 내의 다른 함수명과 충돌될 것 같으면 이 함수를 static으로 선언하면 됩니다. 모듈간에 이름이 겹치게 되더라도 static으로 하면 서로의 정의에 문제가 없어지게 됩니다.

 

통용 범위 구칙

 

변수나 함수 태그 같은 명칭은 상호 구분되어야 하므로 중복되어서는 되지 않습니다. 그래서 같은 이름을 가진 두 변수는 동시에 존재가 불 가능합니다. 다음과 같이 작성하게 되면 오류가 납니다.

1
2
3
4
5
6
7
8
#include<cstdio>
 
void main()
{
    int i;
    double i;
 
}
cs

 

i라는 변수가 정수형으로 선언되었다가 실수형이라는 형태로 중복 선언 되었음을 오류로 출력을 합니다. 이렇게 정의를 하게되면 i라는 변수를 참조할때 정수형인지 실수형인지 참조에서 모호함이 발생하기 때문입니다. 컴퓨터 프로그래밍에서는 논리에 모호한 것은 인정되지 않습니다. 하지만 예외가 있는데 통용범위가 다른 명칭끼리는 같은 이름의 변수를 이용 할 수 있습니다.

1
2
3
4
5
6
7
8
void function()
{
    int i=0;
}
void main()
{
    int i=0;
}
cs

 function함수에서도 i를 정수형으로 main 함수에서도 i를 정수로 선언을 했지만 논리적으로 문제가 없습니다. 왜냐하면 각 함수에 통용범위가 국한되있기 때문에 서로간을 참조하지 않아 논리적으로 문제가 없습니다. 다음으론 전역변수와 지역변수의 관계를 보도록 하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<cstdio>
void func();
int i = 5;
 
void main()
{
    printf("i == %d\n",i);
    func();
}
void func()
{
    int i = 3;
    printf("i == %d\n", i);
}
cs

func라는 함수에도 변수 i가 있고 전역변수에도 i 가 있습니다. 이와 같은경우는 어떻게 될 까요? 다음의 소스는 컴파일이 되지 않을 것 같지만 다음과 같은 결과가 나오게 됩니다.

전역변수는 5로 정의 되어 있고 func라는 함수안에서는 3으로 초기화를 시켜놓았습니다. 전역 변수는 모든 함수에서 참조가 가능합니다. func 함수에서는 printf에 있는 i라는 변수가 무엇인지 혼란을 일으키는 일이 발생하지만 컴파일러는 에러로 처리하지 않습니다. 이런경우에는 통용범위가 작은 변수에 대해서 우선권을 주기때문에 지역변수 우선으로 생각하게 되는겁니다. 그래서 3을 출력하게 됩니다. 대신 func함수에서는 전역변수에 접근을 할 수 없고 이는 지역변수에 가려져있기 떄문에 안되는 것이므로 가시성(Visibillity)가 없다고 표현하게 됩니다. 하지만 전역변수에 접근은 할 수는 있는데 다음 연산자(::)를 쓰면 가능하게 됩니다.

1
    printf("i == %d\n", ::i);
cs

::i가 의미하는것은 전역변수 i 라는 것을 의미합니다.

 

블록 범위

 

앞에서 지역변수란 함수 내부에서 선언된 변수라 하였는데 정확한 표현은 블록 범위입니다. 지역변수는 { }괄호안에서만 통용되는 범위를 블록범위라고 하는데 { }함수가 보통 함수의 시작과 끝을 나타내고 함수 선두에 지역변수를 선언하는 경우가 많기 떄문에 지역변수의 통용범위가 함수 내부가 되는 것입니다. 지역변수의 통용범위는 정확하게 함수 내부가 아니고 선언된 블록의 내부입니다. 그래서 함수 내부에 { } 블록을 만들고 이 안에 지역변수를 만들 수도 있습니다. 이렇게 선언된 변수는 이 블록 밖에서는 사용 할 수가 없습니다.

1
2
3
4
5
6
7
8
9
10
#include<cstdio>
 
void main()
{
    if (1)
    {
        int i = 10;
    }
    i = 5// 선언되지 않았다고 오류
}
cs

다음과 같은 소스는 9번 째 줄에서 오류가 생기게 됩니다. 선언되지 않은 변수를 사용했다면서요. 위의 소스에서 7번 째에 있는 i변수는 if문에 붙은 블록 범위 안에서만 통용되는 변수이기 때문에 안에서만 사용이 가능한 결과가 나오게됩니다. 만약 i라는것을 안에 선언하지 않고 밖에 선언 했었므녀 9번째 줄은 오류가 생기지 않게 될 것 입니다. 함수의 범위 보다 더 좁은 이런 통용범위를 블록 범위라고 합니다. 만약 이미 선언된 변수를 한번더 사용하고 싶다면 다음과 같이 블록 범위를 이용하여 변수를 선언하면 될 것입니다.

 

선언과 정의

 

이제 선언과 정의를 구분하여 볼 때입니다. 비슷한 용어인듯 알고 이 있지만 의미가 한참 다릅니다. 다음과 같이 정확하게 정의할 수 있습니다.

 

 

 역할

 메모리

 정보의 완전성

 중복 가능성

 선언

 알린다.

 사용 안함

 불완전해도 됨

 가능

 정의

 생성한다.

 할당

 항상 완전해야 함

 불가능

선언과 정의의 대상이 되는 것에는 함수, 변수, 타입, 매크로, 태그등 여러 가지가 있지만 그중에서 함수와 변수가 주 대상입니다.

  • 선언(Declaration) : 컴파일러에게 대상에 대한 정보를 알립니다. 함수가 어떤 인수들을 전달받으며 어떤 타입을 리턴하는지를 알리는 원형 선언이 대표적인 선언입니다. 컴파일러에게 정보만 제공하는 것이므로 본체를 가지지 않으며 실제 코드를 생성하지도 않습니다. 그래서 다음과 같이 중복되어도 지장이 없습니다.
    1
    2
    int function(int a, int b);
    int function(int a, int b);
    cs


    일부로 똑같은 걸 중복 선언 하지는 않겠지만 헤더를 인클루드 한다거나 하다보면 겹칠 수 있습니다. 하지만 중복 선언의 경우에 만약 이렇게 하는 경우네는 할 수 없습니다.

    1
    2
    int function(int a, int b);
    double function(int a, int b);
    cs

    다음과 같은 경우는 허용되지 않습니다. 리턴 값이 같고 이름이 같을 때만 중복 선언이 가능합니다.

  • 정의(Definition) : 대상에 대한 정보로부터 대상을 만들떄 정의라는 말을 이용합니다. 정수형 변수하나 int j를 선언하게 되면 메모리 4바이트를 할당 하게 되며 int function(int a, int b){ } 정의로부터 함수의 보체를 컴파일하여 코드를 생성합니다. 정의는 변수의 타입, 함수의 인수 목록을 컴파일러에게 알려 주기도 하므로 항상 선언을 겸합니다. 그래서 함수를 호출부보다 더 앞쪽으로 정의하면 컴파일러가 이 본체를 만들어 내기 때문에 중복되어서는 안 됩니다. 전체 프로그램을 통해 단 한번만 나타나야 하며 두 번 이상 중복할 필요도 없습니다. 만약 정의를 두 번 반복하면 컴파일러는 왜 똑같은 함수를 두번 정의하냐는 에러 메시지를 출력할 것입니다.

 

'Programming > C' 카테고리의 다른 글

C언어 - 배열(Array)(1/2)  (0) 2015.08.13
C언어 - 표준 함수  (0) 2015.08.11
기억 부류(Storage Class) (1/2)  (0) 2015.08.09
C언어 - 함수(function)(4/4)  (0) 2015.08.07
C언어 - 함수(function)(3/4)  (0) 2015.08.05