[C++] C++에서 사용되는 개념 10탄(함수와 스택프레임)

Patrick!·2023년 1월 9일
0
post-thumbnail

C++의 함수에 대하여

함수는 학원에서 배울때도 프로그레밍에서 로직의 모듈화를 위해서 꼭 필요하고 중요한 존재라고 배웠다.
하지만 프로그레밍 언어마다 함수의 특징은 크게 다르지 않지만 조금씩은 차이가 있기 마련이다.

C++ 에서의 함수
일부 작업을 수행하는 코드 블록입니다. 함수는 호출자가 함수에 인수를 전달할 수 있도록 하는 입력 매개 변수를 필요에 따라 정의할 수 있습니다. 함수는 필요에 따라 출력으로 값을 반환할 수 있습니다.
함수는 이상적으로 함수의 기능을 명확하게 설명하는 이름을 사용하여 재사용 가능한 단일 블록에서 일반 작업을 캡슐화하는 데 유용합니다.

함수를 사용함에 있어 가장 중요한 부분은 재사용성 이라는 부분에서 두드러진다.

만약 int main() 이라는 메인 함수에 모든 로직을 쓰게 되면 수많은 반복(중복성)과 효율적이지 못한 코드를 작성(비효율성)이 나타나게 되므로 함수는 매우 중요하다.

함수의 구조 (어느 프로그레밍 언어에서나 같은 구조를 가지고 있을 것이다. )

반환타입 함수이름([인자타입 매개변수(input)]) {
    logic ~~

    return output; (반환하는 타입이 없을 경우에는 생략할 수 있다.)
}

C++ 함수의 작동원리에 대하여 (스택프레임)

다음과 같은 로직이 실행된다면 함수는 어떻게 작동할까??

#include <iostream>
using namespace std;

void printCal (int a, int b) {
	int c = a + b;
    
    return c;
}

int main() {

    int a = 3;
    int b = 3;
    
    int result = printCal(a, b);
    
    cout << "a + b = " << result << endl;
}

스택프레임 (함수를 실행했을때, 어떤 원리로 진행되는지 자세하게 알아보자!)

높은 메모리 주소 -> 낮은 주소로 증가했다가 줄어드는 개념

스택 메모리 영역(함수들 끼리 사용하는 메모장의 개념)은 어떻게 생성되는가 ?
=> 프로그램이 실행될 때, 얼마만큼의 스택을 줄 수 있는지 할당해준다.
(지난 시간에 배운 Stack 영역에 해당하는 부분이라고 볼 수 있다.)

[증가영역]

한 영역(main과 같은)에는 [매개변수, 반환주소값, 지역변수]가 할당되어 있다.

main()에서 func01()를 호출하는 경우, 매개변수를 보내고 반환주소값을 저장하며, func01()의 스택메모리 영역이 형성된다.
(이후에도 같은 방법으로 점차 증가하게 된다.)

[감소영역]

func02() 에서 프로세스가 마무리 되면 반환값을 들고 func01()의 반환주소값을 통해 func01()의 스택메모리 영역으로 돌아간다.
(이후에도 같은 방법으로 점차 감소하게 된다.)

이를 어셈블리 언어로 살펴보면 조금더 확실하게 스택프레임의 구조를 알 수 있다.

이제 자세히 알아보자!

int result = printCal(a, b) 함수가 실행될 때, 우선 매개변수를 오른쪽기준으로 먼저 넣는다.
레지스터를 알고 싶다면, ctrl + alt + g 를 통해 확인할 수 있다.

mov eax, dword ptr [b]
push eax
mov ecx, dword ptr [a]
push ecx

printCal를 call 하고 난 후, 반환 주소값을 넣어줘야한다.

call printCal (07114ABh)
add esp, 6

이후, printCal를 call한 스택 메모리 영역으로 들어가보면
이전 베이스 포인터의 주소값을 push해서 보관하고 있는다. = 이전 스택 메모리 영역의 반환주소값에 해당한다.

jmp printCal (0712570h) 
push ebp

printCal의 스택 프레임을 관리하는 부분에서는 내부적으로 사용할 변수에 대한 영역을 할당하는 공간을 할당한다.
(printCal 안의 int c = a + b;)

mov ebp, esp
sub ebp, 0CCh

mov eax,dword ptr [a]
imul ecx,dword ptr [b]
mov dword ptr [c], eax

retun c;
mov eax, dword ptr [c]

사용한 스택 프레임을 정리하는 구간이며 ret를 통해 반환주소 int main() 의 printCal(int a, int b)에서 수행한 return 값을 esp 에 담는 작업을 진행한다.

add esp, 0CCh
cmp ebp, esp
ret

add esp, 6

해당 작업을 수행하는 시작점에서 결과를 가지고 다시 반환된 종료점까지의 과정을 보면서 함수의 작동원리와 스택프레임에 대해 알 수 있었다.

하지만 이는 시작에 불과하다.... ( C++는 메모리를 조작할 수 있는 특징이 있기 때문이다. )

포인터가 나에게 전하는 말...


포인터는 C++의 양날의 검 ..? 이라 불릴 만큼 득 혹은 독이 될 수 있는 요소를 배우고 나면 함수를 사용할 때, 매우 조심해야할 날이 머지 않아 찾아올 것이다...
profile
C++와 Unreal Engine / C#과 Unity / Katalon Studio를 통한 자동화 테스트 등을 하루하루 공부한 기록

0개의 댓글