공통 [프로그래밍 애피타이저] 6장 프로시저와 함수
2020.04.07 15:21
프로시저와 함수
프로시저와 함수가 왜 필요한가?
프로그램을 작성할 때 어떤 특정 업무(비즈니스 로직)를 코드로 구현합니다. 이러한 코드가 한 부분에서만 필요한 것이 아니고 여러 부분에서 필요하다면 아래와 같이 코드를 구현 할 것입니다.
소스 A Statement1; Statement2; StateMent3; |
소스 B Statement1; Statement2; StateMent3; … |
이렇게 작성하면 어떠한 단점이 생길까요? (좋은 프로그램 작성 방법에서 어는 부분이 위반될까요?)
네, 먼저 소스 코드 부분이 길어집니다. 또 하나는 수정이 생기는 경우 각각 수정을 하기 때문에 유지 보수 면에서
공수가 많이 듭니다. 그래서 자주 사용하는 공통의 코드부분을 모듈화 하는데 이를 루틴 또는 서브루틴 이라고 부릅니다.
프로시저와 함수의 차이점
루틴은 반환 값(리턴)이 있는 루틴과 반환 값이 없는 루틴으로 분리되는데 델파이에서는 전자를 Function(함수),
후자를 Procedure(프로시저)라고 부릅니다. 선언 시에 이 규칙이 지켜지지 않을 경우 컴파일 오류가 발생합니다.
참고로 C, C++, 자바의 경우는 Function, Void Function 이라고 부릅니다.
프로시저와 함수 선언 및 코드구현방법
선언(Definetion)은 컴파일러에게 루틴이름 매개변수의 정보 등을 알려주는 작업입니다. 이후에 설명과 예제는 델파이를
기준로 작성하였으니 참고하십시오. 즉 루틴의 선언 및 구현방법은 프로그래밍 언어에 따라 차이가 있습니다.
또한 델파이 프로그램 구조와 프로젝트를 구성하는 파일들을 먼저 살펴보아야 합니다. 데브기어 동영상 강의를 참조하시면 도움이 될 것입니다. 단 교육 이전의 분들은 여기서는 프로젝트 구조와 파일들은 교육에서 설명합니다.
l 선언방법
Procedure 프로시저 이름(매개변수이름:매개변수타입, 매개변수이름:매개변수타입..);
Function 함수이름(매개변수이름:매개변수타입, 매개변수이름:매개변수타입….):리턴타입
|
함수와 프로시저는 0개 이상의 매개변수 목록을 가진다. 여러 개의 매개변수 사용 시 세미콜론(;) 으로 구분하고 같은 자료형 사용 시 쉼표로 구분합니다. 매개변수는 뒤 부분에서 자세히 설명하도록 하겠습니다.
델파이 소스인 유니트 파일에서 프로시저와 함수를 선언해 보도록 하겠습니다. 이러한 선언은 어느 곳에 해야 할까요?
선언은 Interface부분과 Implementation 부분에 선언하실 수 있습니다. Interface 부분은 자기 유니트의 선언 아래 부분은
물론 외부 유니트에서도 컴파일 하기 전에 바인딩 하여(uses하여) 사용 할 수 있는 영역입니다. 주로 전역변수, 서브루틴들을 선언하는 곳입니다.
Implementation은 원래 인터페이스 선언된 루틴들을 구현하는 곳인데 이 영역에도 함수나 프로시저를 선언할 수 있습니다. 단 여기에 선언된 루틴들은 자기 유니트 선언 이후 부분에서만 사용할 수 있고 외부에서도 사용 할 수 없습니다.
루틴을 선언만하고 컴파일 하시면 다음과 같은 오류 메시지가 표시될 것입니다.
E2065: Unsatisfied forward or external declaration: '%s' (Delphi)
이 오류는 루틴이 선언만 되어 있고 구현부분이 없다는 의미입니다.
이제 루틴을 implementation에 구현해 보도록 하겠습니다.
procedure 프로시저이름(매개변수이름: 매개변수타입, 매개변수이름: 매개변수타입, …); { 선언부 : 구현부에서 사용할 변수,상수,타입 지정 } begin { 구현부 } end; |
function 함수이름(매개변수이름:매개변수타입, 매개변수이름:매개변수타입…): 반환값타입; { 선언부 } begin { 구현부 } Result := 반환값; end; |
위에서 매개변수이름과 타입들은 생략할 수 있습니다. 이를 Short type 라고 합니다. 단 소스의 가독성이나 디버깅 시에
불편하기 때문에 대부분의 개발자들을 기술합니다. 매개변수이름, 타입이 불일치 시에는 컴파일 오류가 발생합니다.
매개변수란(Parameter) 무엇이고 왜 필요한가?
퇴직금을 계산하는 루틴을 작성한다고 가정해 보겠습니다. 퇴직금은 해당 사원의 급여에 근속연수를 곱한다고 정하겠습니다.
그럼 루틴을 수행하기 위해 어떠한 정보가 최소한 필요합니까? 네 해당직원의 입사일자, 급여정보가 필요합니다.
또는 그 직원의 해당 정보를 읽을 수 있는 사원코드가 필요합니다. 이를 해당 루틴의 매개변수라고 부릅니다.
즉 매개변수는 변수의 특별한 한 종류로서, 프로시저, 함수등과 같은 서브루틴의 인풋으로 제공되는 여러 데이터 중
하나를 가리키기 위해 사용됩니다. 여기서 서브루틴의 인풋으로 제공되는 여러 데이터들을 전달인자(argument) 라고 부른다.
보통 매개변수의 목록은 서브루틴의 정의 부분에 포함되며, 매번 서브루틴이 호출될 때 마다 해당 호출에서 사용된
전달인자들을 각각에 해당하는 매개변수에 대입시켜 줍니다.
매개변수의 전달방식
함수 호출 시 인자 전달 방법에는 Call-by-value(값에 의한 호출)와 Call-by-reference(참조에 의한 호출)이 있다 먼저
이 둘을 비교하며 설명한 후, 델파이의 인자 전달 방식에 대해서도 설명하겠습니다.
l Call-By-Value (값에 의한 호출)
l Call-By-Reference (참조에 의한 호출)
델파이에서의 호출방법
l Call By Value
Function Add(x,y:integer):integer
|
l Call By Const
Procedure ShowMessage(const Msg:string)
|
l Call By Reference
procedure TForm28.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin
end; |
l Out 매개변수
Function Test(out sum:integer):integer;
|
매개변수 디폴트 값 지정방법
매개변수 선언 시 기본값 지정이 가능합니다. 맨 뒤의 매개변수부터 연속적으로 기본값 지정 가능
procedure StrDef(AStr: string = '');
procedure StrsDef(AStr1: string = 'a'; AStr2: string = 'b');
procedure IntDef(ANum: Integer = 0);
procedure IntsDef(ANum1: Integer; ANum2: Integer = 0);
procedure IntsDef(ANum1, ANum2: Integer = 0); // 오류발생
|
프로시저, 함수 호출 방법
<선언> procedure Helloworld;
<코딩>
procedure Helloworld; begin ShowMessage(‘안녕하세요’); end;
<호출> Helloworld;
|
함수호출 규칙(Calling Convention)
함수 호출 규칙(calling convention)은 피호출자 함수를 호출하는 과정에서 매개변수를 전달하는 순서 및 매개변수가 사용한 메모리 관리방법 등에 관한 규칙입니다.
루틴을 선언할 때 호출 규칙을 지정할 수 있습니다. 델파이에는 아래와 같은 호출 규칙이 있습니다. 선언하지 않으면
디폴트인 Regiser 방식으로 호출됩니다.
지시어
|
매개변수 전달 순서
|
Clean_Up
|
레지스트리에 매개변수 전달 여부
|
register
|
Undefined
|
Undefined
|
Yes
|
pascal
|
Undefined
|
Undefined
|
No
|
cdecl
|
Left-to-Right
|
Caller
|
No
|
stdcall
|
Right-to-Left
|
Routine
|
No
|
safecall
|
Right-to-Left
|
Routine
|
No
|
Inline 루틴은 무엇이며 왜 필요한가
아래의 그림은 일반 프로시저나 함수가 호출되는 방법을 표시해 놓은 것 입니다. 함수나 프로시저를 호출 하면 해당
루틴이 있는 곳으로 점프하여 루틴의 구현 부분을 수행하고 다시 호출 부분으로 돌아와서 다음 문장을 수행하는 것이
일반적인 호출 방법입니다. 그러한 이 루틴을 자주 호출하는 경우라면 이러한 작업을 반복하기 때문에 프로그램의
실행 속도가 지연 될 것입니다.
그래서 루틴을 선언할 때 inline 지시어를 사용하여 선언하면 호출 부분에 코드 부분을 삽입하여 다음과 같이 실행하는
방법입니다.
이렇게 호출하면 루틴 부분으로 이동하여 실행하는 것보다 실행 속도를 빠르게 할 수 있습니다. 루틴 사이즈가 큰 경우는
inline 함수를 사용하면 전체적으로 프로그램 사이즈가 커지기 때문에 결론적으로 inline 함수는 짧으면서 자주 사용되는
프로시저, 함수에 사용됩니다.
오버로드(overload) 함수
델파이에서는 같은 유니트에 같은 이름의 변수나 루틴들은 선언 할 수가 없습니다. 프로시저, 함수 종류가 다른 경우에도
같은 이름을 사용하지 못합니다.
예를 들어 선언 부분에서 정수형 Add 함수 외에 실수형 Add를 선언하려면 오류가 발생합니다. 만일 Add_int, Add_real
이런식으로 다른 이름으로 각각 선언한다면 호출 시점에 각각의 매개변수의 타입을 체크하여 각각 호출하여야 하는 번거로울 뿐만 아니라 유지 보수 시에 문자 연결하는 Add가 필요한 경우 Add_str 함수를 추가하고 구현함은 물론 호출 부분을 또 수정하셔야 합니다. 이러한 문제를 오버로드 함수를 통해 해결해 보도록 하겠습니다.
오버로드란 같은 이름의 함수를 여러 개 정의하고, 매개변수의 유형과 개수를 다르게 하여 다양한 유형의 호출에 응답하게
하는 방법입니다.
l 오버로드 함수 선언
function Divide(x,y:integer):integer; overload; |
참고: C++자바는 OVERLOAD라는 개념은 동일하나 overload 지시어를 사용하지 않고 선언합니다.
l 오버로드 함수 호출
procedure TForm1.Button7Click(Sender: TObject); begin
Button7.Caption := IntToStr(Divide(12,4)); end; |
procedure TForm1.Button7Click(Sender: TObject); begin
Button7.Caption := FloatTostr(Divide(12.0,4.0)); end; |
첫 번째 호출은 정수형 Divide가 호출되고 두 번째 호출은 실수형 Divide가 호출됩니다.
다른 언어나 다른 프로그램에서 공통의 루틴들을 사용할 수 있는 방법은 교육 과정(DLL 작성과 호출)에서
다루도록 하겠습니다.
다운로드 : 6장 프로시저와 함수.pdf
프로그래밍을 제대로 공부해보고 싶다면, 다음 순서로 진행하시는 것을 권장합니다.
- 프로그래밍 애피타이저 시리즈
- 함께 보면 좋을 도서: 시작하는 사람들을 위한 델파이 프로그래밍
- 함께 보면 좋을 도서: 시작하는 사람들을 위한 델파이 프로그래밍
- [동영상] 데브기어 델파이 기초 시리즈
- 함께 보면 좋을 도서: 델파이 Begin...End
- 함께 보면 좋을 도서: 델파이 Begin...End
- [오프라인 강의] 델파이/C++빌더 기초 강화
- [오프라인 강의] 델파이/C++빌더 윈도우 프로그래밍