프린세스 다이어리

[C] 컴퓨터가 변수를 처리하는 방식에 대하여 정리 본문

C, C++

[C] 컴퓨터가 변수를 처리하는 방식에 대하여 정리

개발공주 2021. 9. 29. 12:00
728x90

 

1. 메모리의 서로 다른 4가지 영역

 

프로그램을 실행하기 위해서는 일단 프로그램이 메모리에 적재돼야 한다. 그러고 나서 CPU가 메모리를 한 줄 한 줄 읽어서 프로그램을 실행하는 것. 따라서 특정 프로그램이 실행되려면 프로그램을 충당할 만큼의 메모리 공간이 필요하다. 흔히 8G, 16G 컴퓨터 메모리가 있는데, 프로그램을 하나 클릭해서 실행하려고 하면 프로그램이 메모리에 적재돼서 돌아간다. 일반적인 컴퓨터의 운영체제는 메모리 공간을 4가지로 구분하여 관리한다. 이 공간들은 서로 다른 역할을 가지고 있다. 

 

코드 영역 한 줄 한 줄 실행할 수 있는 소스코드
데이터 영역 변수 중에서 전역 변수와 정적 변수를 담고 있다.
힙 영역 동적 할당 변수를 담는다.
스택 영역 함수마다 담고 있는 지역변수, 매개변수 등을 담고 있다. 

 

2. 변수의 종류

 

2-1. 전역변수(Global variables)

 

프로그램 내의 어떤 곳에서든 접근 가능하다. 실제로 프로그램을 실행하게 되면, main() 함수가 실행되기도 전에 프로그램의 시작과 동시에 메모리의 데이터 영역에 적재된다. 프로그램의 크기가 커질수록 전역 변수로 인해 프로그램이 복잡해질 수 있기 때문에 이 점 유의해서 코드를 짜야한다. 

 

#include <stdio.h> 

int a = 5;

void changeValue() {
    a = 10;
}

int main(void) {  
    printf("%d\n", a);
    changeValue();
    printf("%d\n", a);
}

전역 변수 a는 main함수 밖에서 선언이 되는데, 전역으로 선언되었기 때문에 changeValue() 함수에서도 따로 선언하지 않고 바로 접근이 가능하다. 

5
10

 

2-2. 지역변수(Local variables)

 

프로그램의 특정 블록에서만 접근할 수 있다. 함수가 실행될 때마다 함수 블록 내부의 변수들이 스택 영역의 메모리에 할당된다. 함수가 끝나게 되면 메모리에서 해제된다. 

 

#include <stdio.h> 

int main(void) {  
    int a = 7;
    if (1) {
        int a = 5;
    }
    printf("%d\n", a);
}

결과가 5일 줄 알았는데 7이었다. main함수의 블록이 있고, 그 안에 if문으로 이루어진 블록이 따로 있는 구조다. if문 안쪽에서 선언된 변수는 그 내부에서만 사용할 수 있는 것이기 때문에 결과물은 7이 된다. 이게 아니라 main함수 내부의 블록에서 만들어진 a 변수의 값을 변경하고 싶다면, 변수를 선언하는 게 아니라 a 값을 재할당하는 방식을 취해야 한다.

 

#include <stdio.h> 

int main(void) {  
    int a = 7;
    if (1) {
        a = 5;
    }
    printf("%d\n", a);
}

이렇게 하면 원하는 대로 5가 출력이 된다.

 

2-3. 정적 변수(Static Variables)

 

특정한 블록에서만 접근할 수 있는 변수다. 전역, 지역변수처럼 메모리에 할당이 되기는 하는데, 특정한 블록에서만 접근할 수 있다는 특징이 있다. 메모리의 데이터 영역에 적재된다. 

 

#include <stdio.h> 

void process() {
    static int a = 5;
    a = a + 1;
    printf("%d\n", a);
}

int main(void) {  
    process();
    process();
    process();
}
6
7
8

프로그램이 실행됨과 동시에 변수 a가 메모리에 적재되고, main 함수에서 process 함수를 불러올 때마다 a에 1이 더한다. 이미 5로 적재된 것은 무시하고 1씩 더해 가면서 출력이 되는 것이다. 

 

2-4. 레지스터 변수(Register variable)

 

메인 메모리 대신 CPU의 레지스터를 사용하는 변수다. 기본적으로 우리가 흔히 알고 있는 메인 메모리보다는 레지스터가 CPU에 가깝기 때문에 훨씬 처리 속도가 빠르다는 특징이 있다. 그러나 레지스터는 한정적이기 때문에 실제로 레지스터에서 처리될지는 컴파일러가 장담할 수 없다. 

 

#include <stdio.h> 

int main(void) {  
    register int a = 10, i;
    for (i = 0; i < a; i++)
    {
        printf("%d\n", i);
    }
    
}

register int a라고 변수를 정의해주면 된다. 속도를 측정하여 비교하기에는 로직이 아주 간단하기 때문에 나중에 측정을 해볼 것이다.

 

3. 함수에서 매개변수가 처리되는 방식

 

매개변수란 함수를 호출할 때 함수에 필요한 값을 넘겨주기 위해 사용하는 것이다. 전달 방식은 값에 의한 전달 방식과, 참조에 의한 전달 방식이 있다. 

 

값에 의한 전달 방식 - 단지 값을 전달하기 때문에, 함수 내에서 변수가 새로 생성된다. 마치 지역변수와 같다고 보면 된다.

참조에 의한 전달 방식 - 주소를 전달하기 때문에, 원래의 변수 자체에 접근할 수 있다. 전역 변수에 가까운 개념이다.

 

#include <stdio.h> 

void add(int a, int b) {
    a = a + b;
}

int main(void) {  
    int a = 7;
    add(a, 10);
    printf("%d\n", a); 
}

add 함수에서 a 변수에 a와 b 값을 더해서 넣어주도록 했고 main 함수에서 add 함수를 불러와 a 값을 변경해주려고 했다. 그런데 결과는 그대로 7이 나왔다. 이는 값에 의한 전달 방식을 사용했기 때문이다. 즉 함수에 넘겨준 매개변수는 add 함수 안에서만 사용되는 add 함수 전용 변수이기 때문에, main 함수의 int a 값은 변화가 없다. a 값을 변경하고 싶으면 참조에 의한 전달 방식을 사용하면 된다. 

 

#include <stdio.h> 

void add(int *a) {
    *a = *a + 10;
}

int main(void) {  
    int a = 7;
    add(&a);
    printf("%d\n", a); 
}

함수의 매개변수로 값이 아니라, 변수의 주소 즉 포인터 값을 넣어준다. 의도한 대로 17이라는 값이 출력된다. 매개변수로 포인터 변수를 보낼 뿐 특별한 함수 형태는 아니다. 

728x90
Comments