함수 (컴퓨터 과학)

**함수**(function), **서브루틴**(subroutine), **루틴**(routine), **메서드**(method), **프로시저**(procedure)는 소프트웨어에서 특정 동작을 수행하는 일정 코드 부분이다. 즉, '특정한 작업을 위해 재활용할 수 있도록 구현한 코드 블록' 또는 '어떤 기능을 수행하는 공간'을 의미한다. 함수는 대부분의 프로그래밍 언어에서 지원하는 기능으로, 하나의 큰 프로그램을 여러 부분으로 나누어주기 때문에 같은 함수를 여러 상황에서 여러 차례 호출할 수 있으며 일부분을 수정하기 쉽다는 장점을 가진다.
# 역사
함수의 개념은 컴퓨팅 머신이 이미 존재한 이후 어느 시점에서 발전하였다. 산술 및 조건 점프 명령은 일찍이 계획되었고 상대적으로 조금씩 변화해왔다. 그러나 프로시저 호출을 위한 특별한 명령들은 여러 해에 걸쳐 상당히 변화되고 있다. SSEM과 RCA 1802와 같은 최초의 컴퓨터들과 마이크로프로세서들은 단일 함수 호출 명령어가 없었다. 함수는 구현할 수 있었지만 프로그래머들이 호출 시퀀스(일련의 명령)를 각각의 호출 영역에 사용해야 했다. IBM 1620, 인텔 8088, PIC 마이크로컨트롤러와 같은 일부 매우 초기의 컴퓨터들과 마이크로프로세서들은 전용 하드웨어 스택을 사용하여 반환 주소를 저장하는 단일 명령 함수 호출을 갖고 있었으며, 이러한 하드웨어는 함수를 겨우 몇 번만 겹쳐 사용하는 것만 지원되었지만 반복적인 함수를 지원하였다. 유니박 I, PDP-1, IBM 1130과 같은 1960년대 중순 이전의 머신들은 일반적으로 호출 규약을 사용하여 명령 카운터를 호출된 함수의 최초의 메모리 지점에 저장하였다. 함수를 여러 번 임의로 겹쳐 사용하는 것을 지원하였지만 반복적인 함수를 지원하지는 못했다. PDP-11(1970년)은 스택 푸시형 함수 호출 명령을 갖춘 최초의 컴퓨터들 가운데 하나이며, 이 기능은 임의로 겹쳐 함수를 사용하는 것과 반복적인 함수를 모두 지원한다. Guy Lewis Steele Jr. AI Memo 443. 'Debunking the "Expensive Procedure Call" Myth; or, Procedure call implementations considered harmful". Section "C. Why Procedure Calls Have a Bad Reputation".
# 기본 개념
{| class="wikitable" |- ! 규약 !! 설명 |- | 값에 의한 호출 || 인자를 평가한 다음 값의 사본을 함수에 전달한다 |- | 참조에 의한 호출 || 인자에 대한 참조로서, 보통 이에 대한 주소가 전달된다 |- | 결과에 의한 호출 || 매개변수 값은 함수로부터 반환 시 인자에 복사된다 |- | 값 결과에 의한 호출 || 매개변수 값은 함수의 진입점에 복사되며 반환 시에도 그렇게 처리된다 |- | 이름에 의한 호출 || 매크로처럼 매개변수를 미평가된 인자식으로 대체한다 |- | 상수값에 의한 호출 || 매개변수가 상수로 취급되는 경우를 제외하고 값에 의한 호출과 비슷하다 |}
# 구조
함수를 지원하는 일반적인 프로그래밍 언어에서는 다음과 같은 구조를 갖는다. * 어떤 루틴에서 함수를 호출한다. 이때 함수가 가지는 특정 변수에 값을 전달하기도 하며, 이 특정 변수를 매개변수(parameter)라고 하며 전달되는 값을 인자(argument)라고 부른다. * 함수가 호출되어 계산을 수행한다. * 함수가 종료되고 실행 흐름이 원래의 루틴으로 돌아온다. 경우에 따라서는 함수가 계산하여 반환된 값(반환값, return value)을 원래의 루틴에서 사용하기도 한다. 일부 프로그래밍 언어에서는 함수와 서브루틴을 구분하기도 한다. 파스칼이나 포트란과 같은 언어는 반환값이 없는 경우를 서브루틴, 반환값이 있는 경우를 함수로 부른다. 반면 C 등의 언어에서는 함수와 서브루틴이 동의어이다. 함수가 결과값을 반환하는 것 이외에 외부에 영향을 주는 작동을 할 경우 부작용이 있다고 부른다. 부작용이 없는 함수를 순수한 함수로 부르며, 하스켈과 같은 순수 함수형 프로그래밍에서는 모든 함수가 순수한 함수이다.
# 장점
* 하나의 큰 프로그램을 여러 부분으로 분리함으로써 구조적 프로그래밍이 가능하다. * 같은 코드를 계속 쓰지 않음으로써 프로그램의 용량을 줄일 수 있고, 다른 부분이나 다른 프로그램에서 같은 코드를 사용할 수 있다. * 함수의 기능과 내부 구현을 분리하는 캡슐화가 이루어진다.
# 언어별 지원

## 비주얼 베이직
비주얼 베이직은 함수를 성격에 따라 Sub와 Function으로 구분하는데, Sub은 독립적으로 프로그램에 접근하며 값을 반환하지 않으나 Function은 특정 값을 반환할 수 있다. Sub은 호출한다고 하며 Call()을 사용하고, Function은 값을 대입하도록 한다. Function형 함수에 특별히 자료형을 부여할 필요는 없다. 이를테면 다음과 같다. Private Sub Note () Print ("안녕하세요") End Sub Private Sub frmMain_Load () Call Note () End Sub frmMain이 로드되면 호출된 Note()가 '안녕하세요'를 출력한다. 반면에, Private Function Note () Note = "안녕하세요" End Function Private Sub frmMain_Load () Dim Text as String Text = Note () Print (Text) End Sub 이 프로그램에서는 frmMain이 로드되면 호출한 Note가 반환한 '안녕하세요'를 출력하게 된다.
## C, C++
C와 C++에서는 서브루틴과 함수를 구별하는 제약 조건이 그다지 까다롭지 않다. 대신 반환형은 항상 일치해야 하며, 반환하지 않는 함수는 void로 선언된다. 추가된 함수를 메인 함수보다 나중에 놓는 경우에는 **함수의 원형**(프로토타입)을 선언해야 한다. 아래는 인자도 받지 않고 아무런 반환값도 없는 함수의 예이다. void my_func(void) { // do something } 다음은 함수의 원형이 어떻게 선언되는지 보여준다. 보통 함수의 반환형, 이름, 인자 목록을 그대로 쓰되 중괄호로 묶인 코드 대신 세미콜론으로 끝내는 형식이다. // header int my_func(char* your_name); // code int my_func(char* your_name) { // ... return x; } 이 외에 C++, 자바 등의 경우, 반환형과 함수 이름은 같아도 인자 목록의 개수나 자료형이 다르면 호출할 때 사용한 인자 목록에 따라 적절한 함수가 호출되도록 컴파일되는 오버로딩 함수를 지원한다.