일부 작업을 수행하는 코드 블록
반환타입 함수이름(매개변수의자료형 매개변수이름) // 매개변수는 없을수도 있고, 여러개 일 수 있음
{
문장1; // 문장은 여러 개일 수 있음
return 반환타입의 변수 혹은 상수 // 반환 값은 하나 혹은 없음(void), return은 여러 개일 수 있으며 꼭 마지막 줄에 있지 않아도 됨
}
void Print3HelloWorld()
{
cout << "Hello World" << endl;
cout << "Hello World" << endl;
cout << "Hello World" << endl;
}
void PrintNumber(int num)
{
cout << "Print : " << num << endl;
return;
}
int main()
{
Print3HelloWorld();
int a = 10;
PrintNumber(a);
PrintNumber(20);
Print3HelloWorld();
return 0;
}
// 출력 결과
// Hello World
// Hello World
// Hello World
// Print : 10
// Print : 20
// Hello World
// Hello World
// Hello World
Print3HelloWorld 함수는 반환값이 없으며(void) 매개변수도 없다(), return 또한 반환값이 없어서 사용하지 않았지만 맨 마지막 줄에 있다고 생각하면 된다.
Print3HelloWorld라는 함수는 세 번의 “Hello World”를 출력하게 만드는 기능을 한다. 그래서 우리가 일일이 출력하는 문장을 치지 않아도 Print3HelloWorld를 호출하기만 하면, 호출한 부분에서 저 세번의 출력을 하게 된다. 이처럼 일반 작업을 캡슐화(묶어서 코드 블록으로 만듬)를 하여 재사용 가능하게 만들었다. main 함수의 맨 마지막에서 다시 한 번 호출하여 세 번의 출력을 대신하였다.
중간에는 정수를 출력하게 하는 함수인 PrintNumber가 있는데, 정수 자료형 매개변수 하나를 받고 함수 내에서는 그 정수 변수를 num이라는 이름을 사용하여 쓴다. 이 함수 또한 반환값은 없다.
int sum(int a, int b) // 이 sum이란 이름의 함수의 반환값은 int형으로 정수 값을 반환, 두 개의 입력 매개변수를 받으며 각각은 a, b라는 이름으로 이 함수 내에서 사용되는 지역변수
{
return a + b; // a와 b를 더한 값을 반환, 이 함수를 호출한 곳으로 보냄
}
int main()
{
int i = sum(10, 32);
int j = sum(i, 66);
cout << "The value of j is" << j << endl;
}
// 출력 결과
// 108
sum이라는 함수는 반환해야하는 값이 정수형이고, sum 함수를 부르기 위해서는 두 개의 인자를 넘겨주어야한다. int i 는 sum을 호출하고 반환되는 값을 사용하는데, sum을 호출할 때 인자로 10과 32를 넣은 후 나온 값이다. sum 함수의 기능은 두 인자를 더한 값을 반환하니 42라는 값이 되겠다. 즉, i는 42라는 값을 초기값으로 갖게 된다. j 또한 마찬가지로 sum을 호출하지만 인자가 42가 들어있는 i와 상수 66을 넣은 후 나오는 반환값 108을 초기값으로 받는다.
갑자기 자료구조 스택을 얘기하는 이유는 함수가 호출될 때 함수가 가지는 공간인 스택 프레임이 만들어지고 이 스택 프레임이 스택을 이용했기 때문이다.
후입선출(Last In First Out) 특성을 가지는 자료구조
(보통 깔끔하게 정돈된) 무더기, (어떤 곳에 물건을 쌓아서) 채우다
스택과 더불어 함수의 호출 방식을 이해하기 위해서는 메모리의 구조를 알아야한다. 메모리의 스택 영역에서 스택 프레임이 만들어지고 함수를 호출할 때 이 스택 프레임을 만들기 때문이다. 스택 영역만 설명하면 되긴하지만 그래도 전체적으로 한 번 설명한다.
프로그램을 실행하면 운영체제는 메모리에 프로그램을 위한 공간을 배정하고 프로그램은 그 공간을 사용한다. 프로그램의 구성은 크게 네 가지로 낮은 주소부터 코드 영역, 데이터 영역, 힙 영역, 스택 영역으로 이루어져있다. 힙 영역은 낮은 주소부터 높은 주소로 점점 사용해나가고, 스택 영역은 프로그램이 할당 받은 높은 주소부터 낮은 주소쪽으로 사용한다.
실행할 프로그램의 코드가 저장되는 영역
프로그램의 전역 변수와 정적 변수가 저장되는 영역
사용자가 직접 관리할 수 있고 관리해야만하는 영역
함수의 호출과 관계되는 지역 변수와 매개 변수가 저장되는 영역
함수가 호출되었을 때 그 함수가 가지는 공간 구조
첫 번째 그림에서 보면 각 함수를 호출할 때마다 아래부터 매개변수(인자), 반환 주소값, 지역 변수 순으로 스택에 쌓고 있다. 이것이 스택 프레임이고 스택 프레임은 각 함수를 호출할 때마다 생성된다. 또한 각 함수의 호출이 끝난 뒤 그 함수의 스택 프레임은 사라진다.
main 함수에서 func10 함수를 호출 할 때 호출한 함수인 main 함수의 스택 프레임은 스택에서 사라지지 않으며, 그 위로 func10 함수의 매개변수, 반환 주소값, 지역 변수가 쌓인다. func10 함수가 끝날 때 이 함수의 스택 프레임이 사라진다. 각 함수의 호출이 끝나면 위 그림의 역순으로 스택 프레임이 하나씩 사라진다.
위에서 설명한 내용은 함수 단위로 스택 프레임을 살펴보았고, 여기에서 스택 프레임 자체에 대해서 좀 더 살펴본다. 함수가 불리는 과정을 가장 로우 레벨 단위로 바라볼 수 있는 어셈블리로 보기위해 어셈블리 용어부터 설명한다.
위의 한 함수의 스택 프레임을 더 세분화하면 다음 그림과 같이 된다.
; 어셈블리에서 주석은 ;로 시작
; 함수의 매개변수(인자)
PUSH 인자3
PUSH 인자2
PUSH 인자1
; 함수의 반환 주소
CALL 함수주소
PUSH EBP
MOV EBP, ESP
SUB ESP, 100H
; 함수의 지역변수
; PUSH 지역변수
; ...
; 함수의 호출 종료 시
MOV ESP, EBP
POP EBP
RETN
; 함수 호출 종료
참고한 글