함수는 "특정한 기능을 수행하기 위해 독립적으로 작성된 코드의 묶음" 으로 정의한다. 함수는 서브루틴(subrouine) 또는 프로시저(procedure) 라고도 불리고 객체지향 프로그래밍 언어에서는 클래스가 가지는 함수를 메소드(method) 라고 한다. 함수는 다음과 같은 장점을 가지고 있어 모든 프로그래밍 언어에서 가장 중요한 요소이다.
-
복잡한 문제를 해결 가능한 작은 문제로 분해하고 분해된 작은 문제의 해결책을 함수로 처리하고 함수를 구조적으로 사용하여 복잡한 문제를 해결하게 된다.
-
같은 코드를 반복적으로 작성해야 하는 문제를 해결한다. 함수로 만들어 사용하면 코드 작성의 중복을 최소화하고 프로그램의 크기를 줄일 수 있다. 또한 함수는 코드의 수정과 유지 보수를 용이하게 한다.
-
캡슐화(Capsulation)가 가능하다. 함수의 내부 구현과 함수 외부와의 인터페이스를 구분하여 인터페이스가 졍해지면 함수 내부 구현을 지속적으로 프로그래머의 실력 향상에 맞추어 진화시킬 수 있다. 이러한 특징 떄문에 이미 만들어진 함수에 대해서 인테피이스의 모습만 알고 있으면 함수의 실제 구현 내용을 알지 못해도 함수의 기능을 이용할 수 있도록 한다.
C++에서 사용할 수 있는 함수는 크게 라이브러리(library) 함수와 사용자 정의 함수(user defined function)로 구분된다.
- 라이브러리 함수: 라이브러리 함수는 컴파일러를 제작한 회사에서 제공하여 컴파일된 기계어 코드를 모아둔 파일을 라이브러리라고 한다.
- 사용자 정의 함수: 사용자가 필요에 따라 직접 만들어서 사용하는 함수로 라이브러리 함수에서 제공되지 않는 함수를 사용자가 목적에 맞게 직접 만들어서 사용할 수 있다.
함수와 관련한 작업은 함수 정의, 함수 선언, 함수 호출이 있다.
- 함수 정의(function definition): 함수의 기능을 수행하기 위한 코드를 작성하는 것이다.
- 함수 호출(function call): 정의된 함수의 기능을 실행하는 것으로, 실행을 위해 필요한 입력 데이터를 전달하고 함수가 기능을 수행하고 결과를 반환하는 경우 반환 데이터의 처리를 고려하여야 한다.
- 함수 선언(function declaration): 함수가 어떤 형태인지를 알려주는 것(선언)이다.
이들 세가지 작업은 컴퍼일러가 이해하고 해석해야 하므로 표현 규칙(문법이라고도 함)이 서로 다르게 규정된다.
이제 함수를 정의할 때 따라야 할 표현 규칙을 알아보자. 함수 정의는 다음 형태를 갖는다.
정의된 함수는 함수 헤더(function header) 와 함수 몸체(function body) 로 이루어진다.
아래의 함수 정의에서 함수 헤더는 반환 자료형 함수이름(매개 변수들)에 해당되며 함수 몸체는 중괄호 {} 로 내부에 해당한다.
함수의 몸체에는 함수가 수행하는 기능을 구현하는데 필요한 프로그램 코드들이 들어간다. 함수 몸체는 실제적인 작업이 이루어지는 영역이다.
함수 몸체에 작성된 코드는 {에서 시작하여 return 문장 또는 }에 도달할 때까지 순차적으로 프로그램 명령어를 하나씩 실행된다.
함수 몸체의 코드가 종료되면 함수를 호출한 곳으로 되돌아 가서 다음 프로그램 코드를 실행한다.
반환 자료형 함수이름(매개 변수들) // 함수 헤더
{ // 함수 몸체 시작
프로그램 코드
} // 함수 몸체 끝 - 반환 자료형(return data type): 함수가 기능을 수행한 후 반환하는 데이터의 자료형을 명시, 이 자료형은 변수를 학습할 때 배웠던 자료형과 같은 개념이다.
함수가 반환하는 데이터가 없을 때는 반환 자료형을 void 로 명시한다. 데이터의 값을 반환하기 위해서는
return키워드를 이용하여 반환하는 값을 반환하여야 한다.return다음에 값, 변수, 수식이 올 수 있다. - 함수 이름(function name): 함수 이름은 사람을 구별할 때 사용하는 이름과 같이 여러 함수 중 특정 함수를 구별하는 식별자 중 한 요소이다. C++에서는 함수의 구분은 함수 이름과 매개 변수의 자료형과 개수의 조합으로 한다. 함수 이름은 함수의 기능을 암시하는 이름을 부여하는 것이 좋다. 보통 함수의 기능을 표현하기 위한 동사 또는 동사와 명사가 조합된 형태로 구성하는 것이 좋다.
- 함수 이름(function name): 함수 이름은 사람을 구별할 때 사용하는 이름과 같이 여러 함수 중 특정 함수를 구별하는 식별자 중 한 요소이다. 함수 이름은 함수의 기능을
- 매개 변수들(argements): 매개 변수는 함수의 기능을 수행하는데 필요한 입력 데이터에 표현하는데 사용된다. 입력 데이터가 없는 경우 매개 변수를 명시하지 않는다. 매개 변수의 개수는 여러 개가 될 수 있다.
- 입력 데이터와 반환 데이터 모두 없는 함수 예
간단한 함수의 예를 통해 함수를 이해하기 위해서 화면에 "Hello!"를 출력하는 함수를 고려하자. 화면에 "Hello!" 만을 출력하는 것이므로 함수에 입력 데이터가 필요 없으며 함수의 기능인 "Hello!"를 화면에 출력한 후 반환할 결과 값이 없다.
함수의 이름은 Greeting 으로 하자. 입력 데이터도 없기 때문에 매개변수도 명시하지 않고 반환 데이터도 없기 떄문에 반환 자료형은 void 이다. 함수 정의의 모습은 다음과 같다.
// Greeting 함수 정의
void Greeting()
{
std::cout << "Hello! "<< std::endl;
}함수 헤더:
void Greeting()함수 몸체:
{
std::cout << "Hello! "<< std::endl;
}- 입력 데이터는 있고 반환 데이터는 없는 함수 예
앞의 함수에서 bool형의 데이터 하나를 입력받고 입력받은 데이터의 상태에 따라 다른 문장을 화면에 출력하는 함수를 고려하자.
입력데이터가 하나가 있어야 하기 때문에 함수를 정의할 때 매개 변수가 하나 명시되어야 한다. 구체적인 함수의 기능은 다음과 같다.
입력 데이터로 bool 형으로 참(true)을 입력받으면 "Hello!" 를 화면에 출력하고 거짓(false)를 입력받으면 "Bye!"를 화면에 출력하는 Greeting 함수를 고려하자.
void Greeting(bool state)
{ // 함수 몸체 시작
if(state == true)
std::cout << "Hello!" << std::endl;
else
std::cout << "Bye!" << std::endl;
} // 함수 몸체 끝함수 헤더:
void Greeting(bool state)함수 몸체:
{
if(state == true)
std::cout << "Hello!" << std::endl;
else
std::cout << "Bye!" << std::endl;
}함수 중 난수(랜덤 숫자)를 생성하는 난수 생성기의 시작 값(seed)을 설정하는 srand 함수가 이 경우에 해당한다.
srand 함수는 시작 값 설정에 사용할 양수의 정수 값을 입력받아 난수를 계산하는 기능에 초기 값을 사용하여 난수를 생성하도록 설정만 할 뿐 반환 값은 없다.
srand 함수의 형태는 다음과 같다.
void srand((unsigned int)seed);srand 함수의 사용은 다음에 살펴보기로 하자.
- 입력 데이터와 반환 데이터 모두 있는 함수 예
두 개의 정수 합을 구하고 결과 값을 반환하는 함수를 고려하자. 두개의 정수의 합을 구하는 함수이므로 매개 변수의 개수는 두 개이고 자료형은 정수를 나타내는 자료형인 int, short, long 등으로 선언한다. 두개의 정수의 합을 구한 후 결과 값을 반환하기 때문에 반환 자료형을 명시해야 한다. 반환 자료형은 매개 변수의 자료형과 같도록 명시해야 한다.
이제는 함수 이름만 정하면 될 것이다. 함수 이름을 sum 이라 하면 sum 함수의 정의는 다음과 같다. 여기서 매개 변수의 자료형을 int로 하자.
int sum (int a, int b)
{
int r;
r = a + b;
return r;
}함수 몸체의 세 줄은 다음과 같이 한 줄로 줄일 수 있다.
return a + b;함수 헤더:
int sum (int a, int b)함수 몸체:
{
int r;
r = a + b;
return r;
}- 입력데이터는 없고 반환 데이터는 있는 함수 예
입력데이터는 없고 반환 데이터가 있는 함수 예로 난수(랜덤 숫자)를 생성하는 난수 생성 함수 rand 가 있다.
rand() 함수는 [0 ~ RAND_MAX] 범위의 정수 중 랜덤한 숫자 하나를 반환한다. RAND_MAX 값은 stdlib 헤더파일에 매크로로 다음과 같이 명시되어 있다.
#define RAND_MAX 0x7fff난수 생성 함수 rand 함수의 원형은 다음과 같다.
int rand(void);다음은 앞에서 살펴본 srand()와 rand()함수를 사용하여 난수를 생성하는 프로그램 코드 이다.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main(int argc, char const *argv[])
{
srand(static_cast<unsigned int> (time(NULL)));
for(int i = 0; i < 10; i++) {
cout << "random number[" << i << "]: " << rand() % 7 << endl;
}
return 0;
}함수의 기능을 실행시키는 것을 함수 호출(function call)이라고 한다. 함수를 호출하려면 함수의 이름을 적으며 함수가 필요로 하는 입력 데이터가 있으면 데이터를 나열하면 된다. 함수 호출도 C++의 하나의 명령문이기 때문에 문장의 끝이 세미콜론(;)붙인다. 또한 함수가 반환 데이터가 있으면 반환데이터를 처리하는 기능이 필요하다.
함수를 호출하게 되면 함수 호출문 다음의 코드의 실행은 잠시 중지되고 호출된 함수의 몸체 내의 문장들이 순차적으로 실행된 후 함수의 실행이 종료되면 함수 호출문 다음 위치로 되돌아 온다.
다음은 앞에서 정의한 함수를 호출하는 예이다.
Greeting();
Greeeting(true);
int s = sum (10, 20);
srand(1);
srand(time(NULL));함수 선언은 컴파일러에게 프로그램에서 사용하고자 하는 사용자 정의함수를 비롯하여 라이브러리 함수의 정보 를 알려주는 것이다. 알려주어야 할 함수의 정보를 함수 원형(function prototype)이라 한다. 함수 원형은 함수의 헤더와 유사한 형태를 가진다. 단 함수 선언에 사용되는 함수의 원형에는 매개 변수의 자료형이 의미를 가진다. 즉 함수 선언은 함수 원형을 코드로 작성하는 것이다.
다음은 앞에서 정의한 함수의 원형이다.
void Greeting();
void Greeting(bool);
int sum(int, int);
void srand(unsigned int);함수 선언은 컴파일러에게 미리 함수 원형에 대한 정보를 제공하여 함수 호출 시 함수의 반환형과 매개 변수의 자료형이 올바른 것인지 검사하도록 한다. 컴파일러가 함수 호출 문장을 해석 및 검사할 때 컴파일러가 함수의 원형을 기반으로 함수 호출문이 올바른지를 검사할 수 있기 때문에 함수 원형을 알려 주는 함수 선언이 함수 호출보다 먼저 이루어져야 한다. 함수의 정의가 함수의 호출보다 앞서 이루어져 있으면 컴파일러가 함수 호출문을 해석할 때 함수 정의를 해석할 때 얻은 사전 정보를 알고 있기 때문에 함수의 정의가 함수 선언의 의미를 동시에 갖게된다.
앞의 C++ 프로그램을 작성하여 실행파일을 생성하기 위해서 main 함수가 사용되었다.
- 프로그램에서 동일한 기능을 반복해서 사용하여야 하는 경우 동일한 기능을 함수로 구현하면 프로그램 코드를 여러 번 작성하는 번거러움을 없앨 수 있다.
- 프로그램을 함수라는 구조적인 프로그램으로 모듈화하기 때문에 프로그램을 수정할 때 모듈 별로 수정할 수 있어 프로그램의 유지 보수가 쉽다.
- 여러 프로그래머가 공동으로 참여하는 프로젝트에서 특정 프로그래머가 작성한 함수를 라이브러리화하여 프로젝트 내의 다른 개발자 들과 공유할 수 있다.