본문 바로가기
Language

[Programming Language] 6. 부프로그램(Subprogram) (1)

by 삼준 2023. 7. 25.
반응형

직전글
2023.07.16 - [Language] - [Programming Language] 5. 문장 수준의 제어 구조
 

● 서론

프로그래밍 언어에서 두 개의 기본적인 추상화 도구로는 프로세스 추상화 도구인 "부프로그램(함수)"와 데이터 추상화 도구인 "클래스"가 있음.
초창기 고급 언어에서는 프로세스 추상화만 반영했음. 명령문장의 묶음을 부프로그램으로 작성 및 재사용함. 이러한 재사용은 메모리 공간과 코딩 시간을 포함하여 절약을 가져왔으며, 프로그램의 가독성을 증가시킴.
또한, 이러한 재사용은 추상화라고 할 수 있음. 부프로그램 세부 사항이 부프로그램을 호출하는 문장에 의해서 대체되기 때문임.
객체지향 언어의 메소드도 부프로그램과 밀접한 관계가 있음. 메소드와 부프로그램의 차이점은 메소드가 호출되는 방법 & 클래스 및 객체와의 연관성임.
 

● 부프로그램의 원리

- 일반적인 부프로그램의 특성

모든 부프로그램은(코루틴 제외) 모두 다음의 특성을 가짐.

메인함수와 f()함수의 예시

  • 단일 진입점을 가짐
  • 호출 프로그램 단위는 피호출 프로그램의 실행 중에 중단됨.(일시정지) 즉, 임의의 주어진 시간에 수행 중인 부프로그램은 오직 하나임.
  • 부프로그램 실행이 끝났을때, 제어는 항상 호출 프로그램에게 돌아감.

 

- 기본 정의들

부프로그램 정의 : 부프로그램 추상화의 인터페이스와 동작을 서술한 것.

정의 예시

부프로그램 호출 : 호출되는 부프로그램을 수행하라는 명시적 요청.

호출 예시

활성 부프로그램 : 호출된 후 실행을 시작했지만, 아직 끝내지 않은 부프로그램.
두 개의 기본적인 부프로그램에는 (1) 프로시저(리턴값 X), (2) 함수(리턴값 O) 가 있음.
 

ㄴ 부프로그램 머리부

부프로그램 정의의 첫 부분.
 
+ 사용 목적
어떤 종류의 부프로그램 (프로시저와 함수가 모두 제공되는 경우)이라는 것을 정의
부프로그램이 이름을 갖는다면, 머리부는 부프로그램의 이름을 제공함.
선택적으로 매개 변수의 리스트를 지정함.
 
+ Python 부프로그램의 머리부

def adder(parameters) :

Python의 모든 부프로그램(함수)은 def로 시작함. 부프로그램의 이름은 adder이며, parameters 자리에 매개변수들이 0개 이상 존재 가능함.
 
+ C 에서 함수의 머리부

void adder(parameters)

머리부에서 예약어 void는 아무 값도 반환하지 않는다는 것을 의미함. (프로시저와 유사하지만 프로시저는 아님)
 

ㄴ 부프로그램 몸체

부프로그램의 동작을 정의하는 부분.
C, C++, Java 등에서는 부프로그램 몸체를 중괄호 (brace, “{“, “}”)로 제한함.
Python 함수에서는 몸체 시작은 문장의 들여쓰기 (indent)로 표시하고, 몸체의 끝은 들여쓰기가 되지 않은 첫 문장으로 표시함.
 
+ Python 함수만의 특징
함수 def 문장이 실행 가능함.

if ... :
  def fun (...) :
    ...
else :
  def fun (...) :
    ...

then 절이나 else 절 둘 중 하나만 선언 및 실행 됨. (오버로딩, 오버라이딩과는 다름)
 

ㄴ 부프로그램의 매개변수 프로파일

형식 매개변수의 개수, 순서 및 타입
 

ㄴ 부프로그램의 프로토콜

프로토콜은 일종의 메뉴얼임.
프로시저의 경우 매개변수 프로파일이고, 함수의 경우 매개변수 프로파일과 반환 타입임.
 

ㄴ 프로그램의 선언

부프로그램은 정의뿐만 아니라 선언도 가짐. 이는 C 언어의 변수 선언과 정의와 비교됨. C 언어에서 선언은 변수를 정의하는 것이 아니라, 타입 정보를 제공하기 위해서 사용함. ("2. 변수, 바인딩, 영역 참고)
부프로그램 선언은 부프로그램의 프로토콜을 제공하지만, 부프로그램 몸체를 포함하지 않음. 따라서 이는 부프로그램의 전방 참조를 허용하지 않는 언어에서 필요함. (ex. main() 함수보다 뒤에 정의된 함수를 main() 함수 앞에서 함수 선언 없이 사용하면 오류 발생)
부프로그램 선언은 C와 C++ 프로그램에서 일반적이며 (프로토타입이라 부름) 종종 헤더 파일에 위치하지만, C와 C++을 제외한 대부분의 언어에서 부프로그램을 호출 전에 정의해야 한다는 요구 사항이 없음. 즉, 부프로그램 선언이 필요하지 않음.
 

- 매개변수

부프로그램에는 두 가지 경우가 있음. (1) 메소드가 아닌 부프로그램과 (2) 메소드
 

1. 메소드가 아닌 부프로그램

C의 부프로그램에 해당(객체지향 X). 메소드가 아닌 부프로그램이 처리할 데이터를 접근하는 두 가지 방법 (지역변수 제외)

  • 비지역변수 (어디선가 선언된, 부프로그램에서 가시적인 변수, a.k.a 전역변수)의 직접적 접근
  • 매개변수 전달을 통해 전달받은 후 접근

매개변수 전달은 비지역변수의 직접 접근보다 훨씬 높은 유연성을 제공함.
비지역 변수의 광범위한 접근은 신뢰성을 감소시킴.
 

2. 메소드

Java의 부프로그램에 해당. 비지역 참조(클래스 변수, 멤버 변수)와 매개변수를 통하여 외부 데이터를 접근할지라도, 메소드에 의해서 처리되는 주요한 데이터는 메소드가 호출된 객체에 속한 것임.
그러나, 메소드가 비지역 데이터를 접근할 때 발생하는 신뢰성 문제는 메소드가 아닌 부프로그램에서와 동일함.
또한, 객체-지향 언어에서, 클래스 변수(객체보다는 클래스에 관련된 변수)에 대한 메소드 접근은 비지역 데이터의 개념과 관계가 있으며 가능한 피해야 함. (C 언어에서와 마찬가지로 함수의 부작용가질 수 있음.)
 

ㄴ 형식 매개변수 (Formal Parameter)

부프로그램 머리부의 매개변수.
이 매개변수들은 통상적인 의미에서의 변수가 아니라 때때로 더미 변수(Dummy Variable)로 생각됨.
이 매개변수들은 부프로그램이 호출될 때만 기억 장소에 바인딩됨.
 

ㄴ 실 매개변수 (Actual Parameter)

호출문에서의 매개변수.
부프로그램 호출문은 부프로그램의 이름과 형식 매개변수에 바인딩되는 매개변수 리스트를 포함함.

ㄴ 형식 매개변수와 실 매개변수의 대응(또는 바인딩) 관련 내용

(1) 위치 매개변수, (2) 키워드 매개변수, (3) 디폴트 값, (4) 가변 개수 매개변수
 
+ 위치 매개변수
거의 모든 프로그래밍 언어에서 형식 매개변수와 실 매개변수의 대응은 단순히 위치에 기반함. (첫 번째 실 매개변수는 첫 번째 형식 매개변수에 바인딩.나머지도 이와 같은 방법으로 이루어짐.)
이러한 매개변수를 위치 매개변수라고 부르며, 매개변수 리스트가 상대적으로 짧은 경우에 효율적이고 안전한 방법임.
 
+ 키워드 매개변수
매개변수 리스트가 길 때, 프로그래머는 위치 매개변수의 사용에 있어서 오류를 범하기 쉬움.
키워드 매개변수에서는 실 매개변수가 바인딩되는 형식 매개변수의 이름이 실 매개변수와 함께 호출에서 지정됨.

# Python
sum_array (length = l, list = arr, sum = s)

장점은 실 매개변수 리스트에서 순서가 자유롭게 바뀔 수 있다는 것이지만, 단점으로는 부프로그램의 사용자가 형식 매개변수의 이름을 알아야 하다는 점이 있음.
Python 등은 키워드 매개변수 이외에 위치 매개변수도 허용하여 혼합 사용이 가능함.

# Python
sum_array (l, list = arr, sum = s)

이 방법의 제약은 키워드 매개변수가 리스트에서 나타난 후에 모든 매개변수는 키워드 매개변수여야 한다는 점. 왜냐하면, 키워드 매개변수가 나타난 후에 위치가 잘 정의되지 않기 때문임.
 
+ 디폴트 값
Python, C++ 등에서 형식 매개변수는 디폴트 값를 가짐.
디폴트 값은 부프로그램 머리부의 형식 매개변수에 실 매개변수가 전달되지 않을 때 사용됨.

# Python 함수 머리부 예
def compute_salary (time, cost = 9620, tax_rate)

형식 매개변수 cost는 compute_salary 호출에서 생략이 가능하며, 생략되는 경우, 값으로 9620을 사용함.
실 매개변수 리스트에서 콤마는 다음 매개변수의 존재를 의미함. 따라서, Python 호출은 생략된 매개변수에 대해서 콤마를 포함하지 않음.

# Python 함수 머리부 예
salary = compute_salary (40, tax_rate = 3.3)
# 중간에 디폴트 값이 생략되어 있음

키워드 매개변수를 지원하지 않는 C++에서, 매개변수는 위치로 연관되기 때문에, 디폴트 매개변수는 마지막에 나타나야 함.

// C++ 함수 머리부 예
float compute_salary (float time, float tax_rate, int cost = 9620)
// 호출 예
salary = compute_salary (40, 3.3);

 
+ 가변 개수 매개변수
형식 매개변수의 디폴트 값을 갖지 않는 대부분의 언어에서 호출의 실 매개변수의 개수는 부프로그램 정의 머리부의 형식 매개변수의 개수와 일치해야 함.
그러나, C, C++, JavaScript 등에서는 요구사항이 아님.
형식 매개변수의 개수보다 호출에서 실 매개변수의 개수가 적을 때, 책임은 프로그래머에게 있음.
오류 발생이 쉽기는 하지만, 이러한 허용은 편리함을 제공함. 예를 들어, C 언어의 printf 함수는 임의의 개수의 항목을 프린트할 수 있음.

// C언어 printf 함수 정의
int printf(const char * restrict format, ...);
// 뒤의 ...이 가변을 의미함

 

- 프로시저와 함수

두 부프로그램의 차이는 반환 값이 있냐(프로시저) 없냐(함수)에 있음.
프로시저를 제공하지 않는 언어에서는 함수가 값을 반환하지 않도록 정의할 수 있도록 허용함. (리턴값 void)
Ada와 Fortran을 제외한 대부분의 언어는 프로시저를 지원하지 않음.
 

ㄴ 프로시저가 결과를 생성하는 두 가지 방법

  • 형식 매개변수는 아니지만 그 프로시저와 호출 프로그램에게 가시적인 변수가 있다면, 프로시저는 그 변수들의 값을 변경함으로써, 결과를 전달함. → 전역변수 변경
  • 부프로그램이 호출자에게 데이터 전달을 허용하는 형식 매개변수를 갖는다면, 그 형식 매개변수를 변경함으로써, 결과 전달함. → 매개변수 변경

ㄴ 함수

함수는 구조적으로 프로시저를 닮았지만, 의미적으로는 수학 함수가 모델임.
함수가 충실한 모델이라면, 함수 부작용은 발생하지 않아야 함. 즉, 함수는 매개변수나 함수 외부에서 정의한 변수를 수정하지 않아야 함. 그런 순수한 함수는 반환하는 값만이 유일하게 결과를 전달하는 방법임.
하지만 실제 대부분의 프로그램 언어에서 함수는 부작용을 가짐.
함수는 새로운 사용자-정의 연산자를 정의함.

// C++에서 지수 연산자 예
// 머리부
float power(float base, float exp)
// 호출
result = 7.2 * power(2.0, x);

C++는 지수 연산자를 제공하는 대신에, 라이브러리로 pow라는 함수를 제공함.
대부분의 언어에서, 사용자는 새로운 함수를 정의함으로써 연산자를 중복하는 것을 허용함. (연산자 오버로딩)
 

반응형

댓글