전체 코드


1. 호출 스택(Call Stack)이란?

호출 스택(Call Stack)은 함수 호출과 실행을 관리하는 데이터 구조로, 후입선출(LIFO, Last In First Out) 방식으로 동작합니다.
즉, 먼저 호출된 함수가 가장 나중에 실행을 종료하며, 나중에 호출된 함수가 먼저 실행을 종료합니다.

🔹 호출 스택의 동작 원리

  1. main() 함수가 실행되면서 호출 스택에 올라감.
  2. main()에서 Func1()을 호출하면, Func1()이 호출 스택에 추가됨.
  3. Func1()에서 Func2()를 호출하면, Func2()가 호출 스택에 추가됨.
  4. Func2()에서 Func3()을 호출하면, Func3()가 호출 스택에 추가됨.
  5. Func3() 실행이 완료되면 호출 스택에서 제거됨.
  6. Func2() 실행이 완료되면 호출 스택에서 제거됨.
  7. Func1() 실행이 완료되면 호출 스택에서 제거됨.
  8. 마지막으로 main()이 종료되면서 프로그램이 종료됨.

2. 호출 스택을 확인하는 방법

📌 디버깅을 활용한 호출 스택 확인

  1. 브레이크 포인트 설정 → 디버깅 모드 실행 (F5)
  2. 한 단계씩 실행 (F10 또는 F11)
    • F10: 함수 내부 실행을 건너뛰고, 호출된 함수의 결과만 확인.
    • F11: 함수 내부로 들어가서 한 줄씩 코드 실행 과정 확인.
  3. 호출 스택(Call Stack) 창 확인
    • Visual Studio 기준: 우측 하단 "Call Stack" 탭에서 확인 가능
    • 어떤 함수가 어떤 순서로 호출되었는지 확인 가능.

3. 호출 스택 예제 코드

✅ 예제 코드 1: 호출 스택 구조 확인

#include <iostream>
using namespace std;

// 함수 선언
void Func1();
void Func2(int a, int b);
void Func3(float a);

int main() {
    cout << "main" << endl;
    Func1(); // Func1 호출 -> 호출 스택에 Func1 추가
    return 0;
}

// Func1 정의
void Func1() {
    cout << "Func1" << endl;
    Func2(1, 2); // Func2 호출 -> 호출 스택에 Func2 추가
}

// Func2 정의
void Func2(int a, int b) {
    cout << "Func2" << endl;
    Func3(10.0f); // Func3 호출 -> 호출 스택에 Func3 추가
}

// Func3 정의
void Func3(float a) {
    cout << "Func3" << endl;
}

📌 실행 결과

main
Func1
Func2
Func3

📌 호출 스택에서 함수가 실행되는 순서

  1. main()이 호출 스택에 추가됨.
  2. Func1()이 호출되어 호출 스택에 추가됨.
  3. Func2(1,2)가 호출되어 호출 스택에 추가됨.
  4. Func3(10.0f)가 호출되어 호출 스택에 추가됨.
  5. Func3() 실행 종료 → 호출 스택에서 제거됨.
  6. Func2() 실행 종료 → 호출 스택에서 제거됨.
  7. Func1() 실행 종료 → 호출 스택에서 제거됨.
  8. main() 실행 종료 → 프로그램 종료.

4. 함수 선언과 정의의 차이

C++에서는 함수 선언을 통해 컴파일러에게 함수가 존재한다는 것을 미리 알릴 수 있습니다.
이는 컴파일 시 함수가 정의되지 않은 상태에서 발생하는 오류를 방지하기 위해 필수적입니다.

✅ 예제 코드 2: 함수 선언 없이 호출할 경우 오류 발생

#include <iostream>
using namespace std;

void Func1() {
    cout << "Func1" << endl;
    Func2(1, 2);  // ❌ Func2가 아직 정의되지 않음 → 오류 발생
}

void Func2(int a, int b) {
    cout << "Func2" << endl;
    Func3(10.0f);
}

void Func3(float a) {
    cout << "Func3" << endl;
}

int main() {
    cout << "main" << endl;
    Func1();
    return 0;
}

📌 발생하는 오류

‘Func2’를 찾을 수 없습니다.

Func1 내부에서 Func2를 호출할 때 Func2가 아직 정의되지 않아서 발생하는 오류입니다.

✅ 해결 방법: 함수 선언 추가

#include <iostream>
using namespace std;

// 함수 선언 (프로토타입)
void Func1();
void Func2(int a, int b);
void Func3(float a);

int main() {
    cout << "main" << endl;
    Func1();
    return 0;
}

// 함수 정의
void Func1() {
    cout << "Func1" << endl;
    Func2(1, 2);
}

void Func2(int a, int b) {
    cout << "Func2" << endl;
    Func3(10.0f);
}

void Func3(float a) {
    cout << "Func3" << endl;
}

📌 실행 결과

main
Func1
Func2
Func3

함수 선언을 통해 정의 순서와 관계없이 올바르게 실행됨!


5. 호출 스택을 디버깅을 통해 확인하기

✅ 호출 스택 디버깅 과정

  1. Visual Studio 또는 GDB에서 브레이크포인트 설정 (Func3() 내부)
  2. 디버깅 실행 (F5)
  3. 호출 스택(Call Stack) 창 확인
    • main → Func1 → Func2 → Func3 순서로 호출됨을 확인 가능.
  4. 한 단계씩 실행 (F11)
    • 실행 흐름을 추적하며 스택에서 제거되는 과정 확인.

📌 호출 스택(Call Stack) 창 예시

Call Stack
Func3()
Func2()
Func1()
main()
  • 가장 아래(main)가 가장 먼저 실행된 함수
  • 가장 위(Func3)가 가장 마지막으로 실행된 함수
  • 실행이 종료되면서 위에서부터 하나씩 제거됨.

6. 정리

호출 스택(Call Stack)이란?

  • 함수 호출 정보를 저장하는 메모리 구조로 LIFO(Last In First Out) 방식으로 동작.
  • 함수가 실행되면 스택에 추가되고, 종료되면 스택에서 제거됨.

함수 선언과 정의

  • 함수 선언(prototype) 을 통해 컴파일러가 함수의 존재를 인식하도록 함.
  • 선언 없이 함수를 호출하면 컴파일 오류 발생.

호출 스택 디버깅

  • 브레이크 포인트를 설정하고 F11을 사용하면 호출 순서를 확인 가능.
  • 호출 스택 창(Call Stack)을 활용하면 실행 흐름을 쉽게 파악할 수 있음.

디버깅을 통해 실행 순서를 분석할 수 있다

  • 함수가 여러 개 호출될 때 호출 순서를 명확히 확인 가능.
  • 프로그램이 예상과 다르게 동작할 경우 디버깅을 활용하여 문제 해결 가능.

profile
李家네_공부방

0개의 댓글