ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 콜 스택 동작을 통해 알아보는 함수 호출
    Programming🧑‍💻/Cpp 2025. 2. 4. 23:29

    콜 스택이란?

    프로그램이 실행되어 메모리에 올라오면, 운영체제는 해당 프로그램을 프로세스라는 실행단위로 관리하면서 필요한 컴퓨팅 자원 (CPU 시간, 메모리 등) 을 할당합니다. 각 프로세스는 자신만의 독립된 메모리 공간을 할당받는데, 이를 프로세스의 메모리 구조라고 합니다.

     

    프로세스는 뭘까?

    프로그램은 컴퓨터가 특정 작업을 수행하기 위해 작성된 명령어들의 집합입니다. 쉽게 말해 우리가 하드디스크에 저장해둔 실행 파일이라고 할 수 있죠. 예를 들어 워드나 크롬 브라우저 같은

    people-analysis.tistory.com

     

    프로세스의 메모리는 크게 다음과 같은 영역으로 구분됩니다. 

    1. 코드(텍스트) 영역: 실행할 프로그램의 코드가 저장되는 영역
    2. 데이터 영역: 전역변수와 정적(static) 변수가 저장되는 영역
    3. 힙(Heap) 영역: 동적으로 할당되는 메모리를 관리하는 영역
    4. 스택(Stack) 영역: 함수 호출과 관련된 정보를 저장하는 영역 

    여기서 스택 영역은 메모리 관리가 함수의 호출(call)을 기준으로 이루어지기 때문에 '콜 스택'이라고도 불립니다. 

    스택이라는 이름처럼 데이터를 쌓았다가 역순으로 처리하는 LIFO(Last In First Out) 구조를 가집니다.

     

    예를 들어 다음과 같은 코드가 있을 때 

    void functionC() {
        // 작업 수행
    }
    
    void functionB() {
        functionC();  // C 호출
    }
    
    void functionA() {
        functionB();  // B 호출
    }
    
    int main() {
        functionA();  // A 호출
        return 0;
    }

     

    콜 스택은 아래와 같은 과정으로 변화합니다. 

     

    함수가 종료되면 스택에서 제거되며, 이전 함수로 돌아갑니다. 

     

    콜 스택 주요 특징 

    메모리 구조 

    • 높은 주소에서 낮은 주소 방향으로 자람
    • 각 함수 호출마다 새로운 영역(스택 프레임) 할당 

    자동 메모리 관리

    • 함수 호출 시 자동으로 스택 영역에 메모리 할당
    • 함수 종료 시 자동으로 메모리 해제 

    실행 컨텍스트 보존 

    • 현재 실행 중인 함수 상태 정보 저장
    • 함수 종료 후 이전 상태로 복원 가능 

     

    콜 스택의 구성 요소 

    스택 포인터 ( Stack Pointer )

    콜 스택에서 스택 포인터는 현재 실행중인 함수의 위치를 가리키는 특별한 레지스터입니다.

     

    베이스 포인터 ( Base Pointer )

    새로운 함수를 호출할 때마다 새로운 스택 프레임이 생성되는데, 베이스 포인터는 이 스택 프레임의 시작 주소를 가리킵니다. 

     

    스택 프레임 ( Stack Frame )

    함수에 실행에 필요한 모든 정보를 포함하는 메모리 블록을 의미하며

    각 함수에 대응하는 스택 프레임은 다음 정보를 포함합니다. 

    1. 함수 매개 변수
    2. 반환 주소 
    3. 이전 베이스 포인터
    4. 지역 변수
    5. 임시 데이터  

     

    다음 코드를 통해 함수 호출시 콜 스택이 어떻게 구성되는지 알아봅시다. 

    void callee(int x, int y) {
        int local1 = x + y;    
        int local2 = x * y;    
    }
    
    void caller() {
        int a = 10;
        int b = 20;
        callee(a, b);         
    }
    
    int main() {
        caller();
        return 0;
    }

     

    1. 프로그램 시작 시점 ( main 함수 진입 전 ) : 이 시점에 스택은 비어있으며, SP와 BP는 동일한 위치를 가리킵니다. 

    2. main() 함수 진입 : main 함수의 스택 프레임이 생성 

    3. caller() 함수 호출 준비 및 진입 : caller 함수의 스택 프레임이 생성되고 지역변수가 초기화됩니다. 

    4. callee(a, b) 호출 준비 (매개변수 푸시) : callee 스택프레임 구성전에 필요한 정보 구성 

    5. callee() 함수 진입 : callee 함수의 스택 프레임 생성되고, 지역변수들이 계산되어 저장 

     

    • SP는 항상 스택의 최상단을 카리키며, 새로운 데이터가 추가될때마다 위로 이동합니다.
    • BP는 현재 함수의 스택 프레임 시작점을 가리키며, 함수 내에서 고정된 위치를 유지합니다. 
    • 함수가 호출될때마다 새로운 BP가 설정되고, 이전 BP는 스택에 저장됩니다. 
    • SP는 매개변수 푸시, 지역변수 할당 등의 작업에 따라 계속 움직이지만, BP는 함수 실행 중에는 고정되어 있어 지역변수와 매개변수의 위치를 찾는 기준점 역할을 합니다. 예를 들어, callee 함수에서 매개변수 x에 접근할 때는 BP를 기준으로 상대적인 위치를 계산해서 접근합니다 (BP + offset). 이런 방식으로 BP는 함수 내의 모든 지역변수와 매개변수에 대한 안정적인 참조 지점을 제공합니다.

    'Programming🧑‍💻 > Cpp' 카테고리의 다른 글

    포인터의 크기는 어떻게 결정될까?  (0) 2025.02.03
    이중 포인터  (0) 2025.02.01
    포인터도 타입이 필요한 이유  (0) 2025.01.31
    변수와 포인터  (0) 2025.01.30

    댓글

Designed by Tistory.