Sign In

[프로그래밍 언어] 6. Subprograms

Y
Yerim
  1. Programming Language

추상화

•
프로세스 추상화: 부프로그램의 형식으로 같은 문장을 반복하여 작성하지 않음
•
데이터 추상화: 사용자가 정의한 추상 데이터 타입

부프로그램

부프로그램

•
인터페이스와 동작을 서술
◦
단일 진입점
◦
호출 프로그램의단위는 피호출 부프로그램의 실행 중 중단
◦
실행이 끝났을 때 제어는 항상 호출 프로그램에게 돌아감
•
부프로그램의 머리부: 부프로그램 정의 → 이름 제공, 매개변수 리스트 지정
•
부프로그램의 몸체
◦
C, C++: {중괄호}, 시행하지 않아도 함수 번역
◦
Java: {중괄호}, 매개변수가 다르면 매개변수 오버로딩 → 정적 타입 언어
◦
Python: 들여쓰기, def 만날때까지 존재 X → 인터프리터 언어 (if-else로 오버라이딩)
#include <stdio.h>
int add(int, int);         // 함수 선언 -> 헤더 파일에 위치
int main(void){add(2, 1);} // 함수 호출
int add (int x, int y){}   // 함수 정의
•
매개변수 프로파일: 형식 매개변수의 개수, 순서 및 타입
•
매개변수 프로파일
◦
프로시저: 매개변수 프로파일
◦
함수: 매개변수 프로파일 + 반환 타입
•
부프로그램 선언: 프로토콜 제공, 몸체 X → 전방참조를 제공하지 않는 언어에서 필요
•
부프로그램 호출: 명시적 요청
•
활성 프로그램: 시작 O, 끝 X

프로시저와 함수

•
프로시저: 반환값 X → 가시적인 변수 / 데이터 전달 허용 매개변수를 변경하여 결과 전달
•
함수: 반환 값 O → 순수 함수는 함수 부작용 X (외부 정의 변수 수정 X, 반환 값만 결과 전달)
◦
프로시저가 없는 언어는 값을 반환하지 않는 void 등의 함수 제공
◦
사용자 정의 연산자 정의 가능 → 대부분의 언어는 연산자를 중복하는 것을 허용

매개변수

부프그램
•
메소드가 아닌 부프로그램: 클래스 외부에 독립적으로 존재
◦
비지역변수: 함수의 외부에서 선언된 변수 → 가시적 변수 직접 접근 시 신뢰성↓
◦
매개변수 전달: 함수 호출 시 전달되는 지역변수 → 유연성 제공
•
메소드: 클래스 내부에에서 객체나 클래스에 의존
◦
메소드가 호출된 객체에 속함
◦
비지역 데이터 접근 시 신뢰성 문제 → 클래스 변수 메소드 접근 최소화
◦
C언어와 마찬가지로 함수 부작용(함수가 결과값 이외 다른 상태 변경)이 발생한다
형식 매개변수와 실 매개변수
def add(a, b): return a + b   # 형식 매개변수 a, b
result = add(3, 5)            # 실 매개변수: 3, 5
•
형식 매개변수: 부프로그램 머리부 매개변수 → 실행 시간 바인딩 (호출 될 때만 기억장소 바인딩)
•
실 매개변수: 형식 매개변수에 바인딩되는 매개변수 = 호출문에서의 매개 변수
바인딩
# 형식 매개변수: income, tax_rate, exemptions
# 키워드 매개변수: exemptions=1 -> 디폴트 값은 1
float compute_pay(float income, float tax_rate, int exemptions=1)
•
위치 매개변수: 형식 매개변수와 실 매개변수는 위치 기반하여 대응 → 효율적, 안전
•
키워드 매개변수: 리스트가 긴 경우 형식 매개변수 이름이 실 매개변수와 함께 호출 (순서 자유)
•
디폴트값: 실 매개변수가 전달되지 않을 때 사용
•
가변개수 매개변수: 실 매개변수는 호출 매개변수 개수와 일치해야함 → 최근엔 컴파일 오류

부프로그램 설계 고려 사항

1.
지역 변수 정적 할당 / 동적 할당 여부 결정
2.
부프로그램의 정의가 중첩 Nested 될 수 있는가
3.
매개변수-전달 방법
4.
부프로그램의 이름이 매개변수로 전달될 수 있는가에 대한 여부
5.
부프로그램의 중복 overloaded 또는 포괄형 generic 부프로그램으로 허용하는가
a.
중복: 동일한 참조 환경 내 다른 부프로그램과 같은 이름
b.
포괄형: 다른 타입의 데이터에 계산을 수행
c.
클로저: 중첩 부프로그램과 중첩 부프로그램의 참조 환경

지역 참조 환경

지역 변수

•
부프로그램은 지역 참조 환경을 정의
int adder(int list[], int listlen){
    static int sum = 0; // 정적
    int count;          // 스택 동적 -> 대부분의 언어에서 디폴트로 스택 동적
    for(count = 0; count < listlen; count++) sum+=list[count];
    return sum;
}
스택동적
•
부프로그램이 실행을 시작할 떄 기억 장소에 바인딩 → 실행이 끝날 때 기억장소 해제
•
장점: 유연성을 제공 (재귀 부프로그램)
•
단점: 할당, 초기화, 해제하는 시간 비용 필요 / 과거 민감형이 될 수 없음
정적
•
장점: 스택-동적 변수에 비해 효율적 / 오버헤드가 없음 / 직접적으로 접근
•
단점: 재귀 호출 부프로그램 지원 못함

중첩 부프로그램

•
부프로그램 (A)를 부프로그램 (B)안에 정의 → 정적 영역이 일반적으로 사용
•
포함 부프로긂에 있는 비지역 변수에 대한 접근 허용
•
Java 8 이후 람다식에서 허용 / Python 부프로그램 중첩 허용

매개변수-전달 방법

매개변수 전달

•
값 복사 / 접근 경로 (단순 포인터, 참조)
•
입력 모드: 값 전달
•
출력 모드: 결과 전달
•
입출력모드: 값-결과 전달, 참조-전달,
이름-전달

입력 모드 - 값 전달

값 전달
•
매개변수가 값으로 전달될 때 형식 매개변수를 초기화 → 형식 매개변수는 지역 변수로 사용
•
값을 스택 장소에 저장
•
장점: 값 전달은 보통 복사로 구현 → 연결 비용과 접근 시간이 빠르다
•
단점: 부가적인 기억 장소가 할당되어야 한다 → 배열 처럼 사이즈가 크면 비용이 많이 필요

출력 모드 - 결과 전달

void Fixer(out int x, out int y){
    x = 17;
    y = 35;
}
f.Fixer(out a, out a);
void DoIt(out int x, out int index){
    x = 17;
    index = 42;
}
sub = 21;
f.DoIt(list[sub], sub);
결과 전달
•
형식 매개변수는 지역변수 처럼 사용 → 반환되기 바로 전에 실 매개변수로 전달 됨
•
값-전달의 반대로구현 → 실 매개변수에 배정된 값은 스택에 놓여짐
•
장점: 연결 비용과 접근 시간 관점에서 빠르다
•
단점: 추가적인 기억 장소와 복사 연산 필요 / 실 매개변수와 충돌
◦
f.Fixer(out a, out a): x, y에 다른 값을 반환할 수 있음 → 복사 순서가 값 결정
◦
f.DoIt(list[sub], sub);: index=42 실행 순서에 따라 list[sub]가 달라짐

입출력 모드 - 값 결과 전달, 참조 전달, 이름 전달

값 결과 전달
•
값 전달 + 결과 전달 →값-결과 전달 (복사 전달)
•
형식 매개변수를 초기화하는 데 사용 → 지역변수로 사용 (값은 실 매개변수로 반환)
•
스택 장소는 호출에 의해서 초기화, 지역변수 처럼 사용
•
장점: 별칭 상황 제거 가능
•
단점: 값 전달, 결과-전달의 단점을 모두 포함
참조 전달
•
접근 경로를 피호출 부프로그램에 전달 → 실 매개변수를 공유
•
실 매개변수의 주소가 스택에 놓여짐
◦
리터럴: 리터럴 주소 / 표현식: 표현식의 결과값 저장된 메모리 셀의 주소를 스택에
◦
리터럴, 표현식 → 값을 변경하는 것을 컴파일러가 막아야 함
•
장점: 시간과 기억 장소 관점에서 효율적 → 기억 장소 중복 X, 복사 X
•
단점:
◦
간접 주소 → 느림
◦
부주의하고 오류적인 변화 → 실 매개변수를 행해질 수 음
◦
별칭 생성 → 가독성↓, 신뢰성↓, 검증 어려움
// 별칭 생성 방법
// 1. 실 매개변수 사이 충돌
void fun(int &first int &second){...}
fun(total, total);

// 2. 배열 원소 사이의 충돌
fun(list[i], list[j]) // i = j

// 3. 배열의 원소 vs 배열
fun(list[i], list);
// 4. 형식 매개변수 vs 비지역변수
int *global; // tree의 root
void sub(int *param){...}
void main(){
    sub(global);
}
이름 전달
•
광범위하게 사용되는 언어에서 사용되지 않음

매개변수 부프로그램 스택

•
값 전달 매개변수: 값을 스택 장소에 복사
•
결과 전달 매개변수: 값 전달의 반대
•
값-결과 전달 매개변수: 값-전달 + 결과-전달
•
참조-전달 매개변수: 실매개변수 주소가 스택에 저장
void swap(int *a, int *b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
    a = 1000;
}
void swap(int *a, int *b)
{
    *a += *b;
    *b = *a - *b;
    *a = *b - *a;
}

언어별

일반적인 언어
•
C: 값 전달
•
C++: 값 전달 (참조 타입 → 역 참조 가능)
•
Java: 값 전달 (참조 변수로 전달, 스칼라 X, 객체는 가능)
•
Python: 배정 전달 (참조 변수 → 참조 전달 → 값 전달)
address(mat[i, j]) = address(mat[0, 0]) + i * number_of_columns + j
*(mat_ptr + (i * num_cols) + j) = x;
다차원 배열
•
C: 행 우선 순서 → 기억 장소 - 사상 함수 (실행 시간 서술자 X → 열 개수 필요),
각 행은 다른 길이 가능
•
Java: 배열은 1차원 → 원소가 배열이 될 수 있음, 각 행은 다른 길이 가능

간접 부프로그램 호출

•
이벤트 처리: 거의 모든 Web응용에서 사용
•
콜백: 호출된 부프로그램 자업 종료 시 호출자에게 알리는 이벤트
int myfun2(int, int);    // 함수 선언
int (*pfun2) (int, int); // 함수 포인터를 생성
...
pfun2 = myfun2;          // 포인터에 배정
...
(*pfun2)(first, second); // 역참조
...
pfun2(first, second);    // 역참조 X
f = foo
•
C, C++: 포인터
•
Python: 소괄호 X → 함수 포인터
•
Java: 포인터 X

중복 부프로그램

중복 연산자
•
피연산자의 타입에 의해서 결정
중복 부프로그램
int fun(int x)
float fun(int x)
void fun(float b=0.0)
void fun()
•
같은 참조환경, 다른 부프로그램과 이름이 같은 부프로그램
•
고유한 프로토콜을 가짐 → 실 매개변수 리스트, 반환 값 타입으로 결정
•
C, Java: 같은 이름 부프로그램(오버로딩) → 변수 타입으로 모호함 해결
혼합형 표현식 → 모호성 제거 X → 일부는 컴파일 실패

포괄형 부프로그램

•
소프트웨어 재사용 → 생산성 증가의 중요한 공헌자
•
여러 개의 다른 부프로그램 생성 필요성을 줄이면 재사용성 증가 가능
•
다형 부프로그램: 활성화 시점마다, 다른 타입의 매개변수를 취할 수 있는 부프로그램
중복 부프로그램의 특이 다형성을 제공
•
부타입 다형성: 객체-지향 프로그래밍 언어들이 일반적으로 지원하는 다형성 (타입 <T>)
•
매개변수 다형성: 포괄형 매개변수 → 포괄형 부프로그램

함수 설계 고려 사항

•
함수 부작용: 명령형 언어 (별칭) ↔ 순수 함수 언어
•
반환 타입: 명령형 언어들은 반환 타입을 제한
◦
C: 배열, 함수를 제외한 모든 타입
◦
Python: 모든 타입 값 반환 가능
◦
Java: 메소드를 제외한 임의의 타입이나 클래스
•
반환 개수: 명령형 언어들은 한 개의 값만 함수로 반환 가능
◦
Ruby: 값이 없을 경우 nil 반환, 배열 반환
◦
Python: 튜플 반환

사용자-정의 중복 연산자

def __add__(self, second):
    return Complex(self.real + second.real, self.image + second.image)
•
메서드 오버로딩 → 파이썬 불가능 → profile로 구분 X
•
Java: 객체 설정 X → 자동부여 this
•
Python: 객체 설정 O, 명시적 전달 → self

클로저

•
부프로그램과 +부프로그램의 참조 환경
•
중첩 부프로그램 허용하지 않는 경우: 클로저 지원 X
◦
호출되는 장소에 관계 없이 접근 가능
◦
C언어 → 전역변수 DS, 지역변수 stack
•
중첩 부프로그램 허용: 클로저 지원 O
◦
부프로그램이 매개변수 전달
◦
부프로그램이 변수에 배정되어 호출
◦
활성화 기간 무제한 → 힙 동적

코루틴

•
실행을 중단했다가 다시 이어서 실행 가능한 서브루틴
•
호출, 피호출 프로그램이 대등한 위치 → 호출 대신 리쥼이라고 부름
•
과거 민감형 정적 지역변수
•
Python Generators
Yerim-DevNote
Subscribe to 'Yerim-DevNote'
Subscribe to my site to be the first to receive notifications and emails about the latest updates, including new posts.
Join Slashpage and subscribe to 'Yerim-DevNote'!
Subscribe
👍