본문 바로가기
PM으로 성장하기/개발 공부

[컴과] 프로그래밍 언어: 정의, 동작원리, 언어 패러다임, 종류, 구성요소

by 고양이 고씨 2022. 11. 12.

프로그래밍 언어란

출처:www.urbanbrush.net


프로그램은 컴퓨터의 명령어를 나열한 것이며, 프로그래밍 언어는 프로그램을 만드는 언어이다. 컴퓨터가 특정한 일을 수행할 수 있도록 컴퓨터와 소통하는 언어이다. 처음에는 컴퓨터가 이해할 수 있는 기계어로 시작되었지만, 점차 사용자가 쉽게 작성할 수 있도록 사용자 친화적인 언어가 탄생하게 되었다. 이러한 배경을 바탕으로 다시 정의하면, 프로그래밍 언어는 컴퓨터가 수행할 수 있고 동시에 사람이 읽을 수 있는 계산이라 할 수 있다.


프로그래밍 언어의 동작 원리

컴퓨터에게 일을 시키려면, 컴퓨터가 이해할 수 있는 언어인 기계어로 명령해야 한다. 기계어는 이진수 형태로 되어있는데, 이진수란 0과 1로 이루어진 것이다. 사람이 직접 0과 1로만 프로그램을 만들 수 없어, 어셈블리어가 등장하게 되었다. 어셈블리어는 기계어에 거의 일대일 대응하는 형태이다. 하지만 어셈블리어는 CPU마다 각각 다르기 때문에, CPU에 종속적이다. 주로 기계어와 어셈블리어를 '저급언어'라고 한다.

어셈블리어로 만든 롤러코스터타이쿤(출처: 나무위키)


이후 '고급 언어'가 등장하는데, 사용자에게 친숙한 표현으로 프로그램을 작성할 수 있는 언어들을 주로 일컫는다. 사용자는 이해할 수 있게 되었지만 컴퓨터는 이해할 수 없기 때문에, 사용자가 입력한 프로그램을 컴퓨터가 이해할 수 있도록 번역하는 과정이 필요해졌다.

이러한 번역을 도와주는 것이 컴파일러와 인터프리터이다.

컴파일러


컴파일러는 사용자가 작성한 프로그램을 CPU가 이해할 수 있는 목적 프로그램으로 바꾼다. 이후 CPU는 목적 프로그램을 실행시켜 출력한다. 조금 더 구체적으로 살펴보면 사용자 프로그램을 어휘 분석, 구문 분석, 의미 분석, 코드 최적화, 코드 생성, 목적 코드 최적화, 목적 프로그램 생성 순서대로 이루어진다.

1. 어휘 분석: 프로그램의 문자로부터 토큰을 만들어내며, 속성을 구분한다. 참고로, 토큰은 문법적으로 의미를 갖는 최소한의 단위를 말한다. 토큰의 종류로는 연산자, 구분자, 식별자, 예약어 등이 있다. 연산자는 +, - 특별한 연산을 수행하는 함수를 말한다. 구분자는 ,(콤마), [] 등과 같이 구분해주는 것을 의미한다. 식별자는 변수나 함수의 이름을 나타내며, 예약어는 프로그래밍 언어에서 정의되어있는 토큰(if, for 등)을 의미한다.
2. 구문 분석: 구문 규칙을 잘 따르고 있는지를 체크하기 위해, 앞서 어휘 분석에서 나온 토큰을 통해 구문 트리를 생성한다. 아래 그림과 같이 문장을 트리 구조로 나타낸다. 구문트리 형태로는 파스트리, 추상 구문 트리 등이 있다. 파스트리는 구문 규칙을 이용하여 문법적 오류가 없는지 체크하기 위해 트리로 나타낸 것이다. 파스트리가 만들어지지 않는다면 오류가 있는 표현이며, 만들어진다고 하더라도 문법상 모호한 부분이 있다면 내부 규칙에 따라 해석한다.

출처: 위키백과


3. 의미 분석: 식별자의 선언 여부, 타입 검사 등을 수행한다.
4. 중간 코드 생성: 구문 트리를 바탕으로 타입 검사를 실행한 후 중간코드를 만든다.
5. 코드 최적화: 비효율적인 코드를 찾아 최적화를 한다. 예를 들어, a=5 b=a+5라면 a=5 b=10으로 치환 등을 수행한다.
6. 목적 프로그램 생성: 최적화된 중간 코드를 기계어로 번역한다.

컴파일러는 바로 뒤에 설명한 인터프리터보다 실행 속도가 빠르다. 하지만 목적프로그램이 컴퓨터마다 다를 수 있는, 하드웨어에 종속적인 단점이 있다. 또한 수정사항이 발생하면 프로그램을 통으로 컴파일해야하므로 수정이 용이하지 않다. 컴파일 언어로는 C 종류가 있다.
위 그림에서는 빠져있지만 링커(Linker)라는 개념도 컴파일 과정 중 하나이다. 링커는 컴파일러가 만들어낸 목적 파일과 라이브러리를 묶어주는 작업을 수행한다. 링커가 작업을 진행하면 실행 파일이 만들어진다.

인터프리터


인터프리터는 프로그램의 소스 코드를 한 줄씩 기계어로 번역하여 바로 출력한다. 컴파일러와 마찬가지로 어휘, 구문, 의미분석을 하고, 중간표현이라는 것을 만들어 인터프리터 엔진에서 실행시킨다. 실행할 때마다 번역과 실행 과정을 거쳐야 하므로 컴파일러에 비해 속도가 느리다. 인터프리터가 번역해야하는 프로그래밍 언어는 스트립트언어라도 불린다. Javascript, Python, PHP, Ruby 등이 여기에 해당한다.

또한 컴파일러와 인터프리터를 결합한 하이브리드 방식도 있다. 사용자가 작성한 프로그램을 컴파일러로 번역하여 중간코드가 생성되면, 가상머신을 활용하여 인터프리터 방식으로 하드웨어에 실행시킨다. Java가 이 경우이다. Java는 컴파일 시 .class 라는 파일로 컴파일된다. 이후 JVM이라는 가상머신을 이용하여 자바가 실행되면 이 코드를 한줄 씩 번역하여 CPU가 실행한다.


프로그래밍 언어의 패러다임


패러다임이란 사물에 대한 이론적인 틀이나 체계를 의미하는 개념으로, 프로그래밍 언어에도 여러 가지 패러다임이 있다. 하나의 언어는 여러 패러다임을 지원하며, 지원하지 않는다고 하더라도 사용자가 어떻게 사용하느냐에 따라 해당 패러다임을 구현할 수 있다.

1. 명령형 프로그래밍
CPU의 작업 순서에 맞추어 명령어를 나열하는 방식이다. 명령어가 순서대로 나열되어 있으므로 프로그램을 이해하기 쉽지만, 프로그램이 복잡한 경우라면 오히려 효과적이지 못할 수 있다.

2. 절차형 프로그래밍
복잡한 문제를 처리할 때 작은 문제로 쪼개어 하나씩 처리하는 방식이다.

3. 함수형 프로그래밍
데이터를 다룰 때 메모리보다 값 자체에 집중하는 방식이다. 데이터는 값으로, 명령어는 함수로 다룬다.

4. 논리형 프로그래밍
참, 거짓과 같은 논리를 사용하여 프로그램을 표현하는 방식이다.

5. 객체지향 프로그래밍
데이터를 중심으로 두고 데이터에 적용할 수 있는 절차를 객체라는 묶음으로 작성하는 방식이다. 객체는 상태를 유지하면서도 외부의 요청에 반응하는 데이터로서, 필드(멤버변수)와 메소드(멤버함수)로 구성된다. 필드는 객체의 상태를 정의하는 속성을 저장하고 있으며, 메소드는 객체를 어떻게 처리할지에 대한 내용을 담고 있다. 클래스는 이러한 객체들의 묶음이며, 클래스를 통해 생성된 객체를 인스턴스라고 한다.

이렇게 글로만 보면 이해하기가 어려운데, 이를 게임 캐릭터에 비유한 아래 설명을 읽으면 이해하기 쉽다.

 

파이썬 코딩 도장: 34.1 클래스와 메서드 만들기

Unit 34. 클래스 사용하기 ​클래스는 객체를 표현하기 위한 문법입니다. 예를 들어 게임을 만든다고 하면 기사, 마법사, 궁수, 사제 등 직업별로 클래스를 만들어서 표현할 수 있습니다. ▼ 그림 3

dojang.io


프로그래밍 언어의 종류

프로그래밍 언어는 컴퓨터의 발전과 시대적인 요구사항에 의해 발전해왔으며, 여러 가지 언어들이 탄생하였다.
1950년대에는 Fotran, Algol, LISP 등이 등장하였고, 1960년대에는 Cobol, PL/I, BASIC, Simula 등이 등장하였으며, 1970년대에는 Pascal, C, Prolog, Smalltalk, Ada, ML, Scheme 등 이 등장하였으며, 1980년대에는 Common LISP, Objective-C, C++, Perl 등이 등장하였고, 1990년대에는 Java, JavaScript, Python, Haskell 등이 등장하였다.
각 언어마다 특징이 있지만, (내 기준) 흔히 접하는 언어들에 대해서만 간략하게 소개하려고 한다.

1. C
서버에서 사용하는 운영체제인 Unix를 개발하기 위한 시스템 프로그래밍 언어이다. C언어에서는 '포인터'라는 개념이 있는데, 이 포인터를 이용하면 메모리의 주소까지도 컨트롤할 수 있다. C언어는 Objective-C, C++, JAva, C# 등 다양한 언어에 영향을 주었다.

2. Objective-C
C 언어에 Smalltalk 언어의 스타일을 결합한 객체 지향 언어이다. 애플의 OS X와 iOS에서 사용되고 있는 언어이다.
- 객체 지향: 컴퓨터 프로그래밍의 패러다임 중 하나로, 프로그램이 명령어의 나열이 아닌 객체들의 모임으로 보는 형태이다. 객체들은 메시지를 주고 받고 데이터를 처리할 수 있다.
- Smalltalk: 프로그래밍 언어 중 하나로, 객체지향 언어이며 최초로 GUI를 제공하는 언어이다.

3. Java
객체 지향 언어이다. 원래 목적과는 다르게 웹 애플리케이션 언어로 발전하면서 인기를 끌기 시작했다. 자바는 JVM이라는 가상머신을 통해 CPU나 운영체제에 관계없이 JVM만 설치하면 어디서나 실행이 가능하다.

4. JavaScript
Java와 이름이 비슷하지만 전혀 다른 언어로, 객체 기반의 스크립트 언어이다. 웹 브라우저 내에서 주로 사용한다.

5. Python
최근 각광받는 언어이자, 프로그래밍 언어 입문용으로 많이 접하는 언어이다. 타입을 고정하지 않고 실행 시 상황에 맞춰 동작하기 때문에, 유연하다는 장점을 갖고 있다.


데이터

프로그램이 처리할 수 있도록 숫자, 문자, 문자열 등으로 나타낸 것을 데이터라고 한다.


연산과 연산자

연산이란 데이터를 처리하는 방법을 말한다. 연산을 적용하면 새로운 데이터를 결과로 얻을 수 있다. 연산자는 특별한 연산을 수행하는 함수를 말한다. 연산은 프로그래밍 언어에서 기본적으로 제공하는 연산이 있고, 사용자가 직접 정의한 연산이 있으며, 사용자가 주로 사용할 만한 연산을 미리 정의한 라이브러리 형태가 있다.


변수 (+ 바인딩)

변수는 프로그램에서 처리할 데이터를 저장하고 관리할 수 있도록 메모리 주소에 이름을 붙인 것이다. 변수는 4가지 속성으로 이루어진다.
1. 변수명: 변수의 이름(식별자)
2. 타입: 변수에 저장할 수 있는 데이터 집합의 종류
3. 주소: 변수가 사용하는 메모리의 위치
4. 값: 변수에 저장된 데이터
예를 들어 정수형 변수 x가 10 이라고 한다면 int x = 10으로 표현할 수 있다. 이 때 x는 변수명이며 int(정수형)은 타입이 된다. 또한 10은 값이 되며, 값 10이 메모리 어딘가에 저장되어있는데, 해당 메모리의 위치가 주소이다.

위 속성은 특정 시점에 구체적으로 결정되는데, 이를 바인딩이라고 한다. 바인딩이 이루어져야 변수를 사용할 수 있다. 바인딩이 일어나는 시점에 따라 정적바인딩, 동적바인딩으로 분리할 수 있다.
- 정적바인딩: 언어가 정의되는 시점, 언어가 구현되는 시점, 컴파일 시점, 링크 시점, 로드 시점에 바인딩 되는 것
- 동적바인딩: 프로그램이 수행되는 시점에 바인딩되는 것
쉽게 구분하자면 정적 바인딩은 프로그램 수행 전에 바인딩되는 것으로서, 프로그램을 수행할 경우 바인딩의 변화가 없다. 반면 동적 바인딩은 프로그램 수행 시점에 바인딩의 변화가 있는 것이다.

그렇다면 각각의 속성은 어떻게 바인딩되는 것일까?

1. 변수명
변수명은 선언문이 있는 경우에 결정된다. 선언문이 없다고 하더라도, 대입연산자를 사용하여 바인딩할 수도 있다. 아래 예시처럼 x를 선언하거나, 선언문 없이 대입 연산자를 통해 바인딩 된다.

int x
y = 10

2. 타입
타입은 선언문에서 명시할 수도 있고, 대입연산자를 사용하여 대입할 값으로부터 정해질 수도 있다. 위의 예시에서 x는 int 형으로 정의되어있으며, y는 별도의 정의는 없지만 10이라는 정수를 대입함으로써 정수형으로 결정된다.
바인딩 시각에 따라 정적 타입 바인딩과 동적 타입 바인딩으로 나눌 수 있다. 정적 타입 바인딩은 컴파일 시점에, 동적 타입 바인딩은 변수의 타입을 고정하지 않고 값에 맞게 계속 변화하는 것을 말한다.

3. 주소
주소는 변수가 사용할 메모리가 할당되어 변수의 주소가 결정되는 것을 말한다. 메모리를 배정할 때 보통 '할당된다'라는 표현을 사용한다. 변수를 미리 선언했다면 자동으로 메모리를 할당받아 코드, 정적 데이터, 스택에 저장되는 자동할당 방법이 있다. 또한 프로그래머가 지정한 크기 만큼 메모리를 할당받아 힙에 저장할 수도 있는데 이를 수동할당 방법이라고 한다. 변수가 메모리를 할당 받게 되면 변수가 수명이 생겼다고 표현하며, 변수의 수명이 없다면 변수 사용이 불가하다.

메모리의 구조

여기서 메모리의 구조를 잠깐 살펴보려고 한다. 프로그램이 실행되기 위해서는 프로그램이 먼저 메모리에 로드 되어야 한다. 운영체제는 메모리 공간을 제공하고 있는데 코드 영역, 데이터 영역, 스택 영역, 힙 영역으로 구분된다.
- 코드 영역에는 실행할 프로그램 코드가 저장되는 영역으로, CPU가 하나씩 처리한다
- 데이터 영역에는 전역 변수와 정적 변수가 저장되는 영역으로, 프로그램의 시작과 함께 할당되고 종료할 때 소멸된다
- 스택 영역은 지역변수와 매개변수가 저장되는 영역으로, 함수가 호출되면 할당되고 함수의 호출이 완료되면 소멸한다
- 힙 영역은 사용자의 의해 할당되는 영역이다

주소도 마찬가지로 바인딩 시각에 따라 정적 주소 바인딩과 동적 주소 바인딩으로 나눌 수 있다. 정적 주소 바인딩은 프로그램을 로드하는 시점에 주소가 바인딩되어 프로그램이 끝날 때 까지 유지하는 것이다. 정적 주소 바인딩이 이루어진 변수는 정적 변수라고 부르며, 보통 변수의 수명은 프로그램의 수행 전체이다. 반면 동적 주소 바인딩은 프로그램 수행 중에 변수가 사용되는 시점에 주소가 바인딩되는 것이다. 동적 주소 바인딩이 이루어진 변수는 동적 변수라고 하며, 자동할당이 되었다면 스택에 저장되므로 스택 동적 변수, 수동할당이 되었다면 힙에 저장되므로 힙 동적 변수라고 부른다.

다음으로, 변수에 있어 중요한 개념 중 하나인 '영역'에 대해 알아보려 한다. 변수의 영역이란, 프로그램에서 변수를 사용하는 범위를 말한다. 코드를 보면 { } 로 이루어지는 문장의 묶음 형태를 많이 보았을 것이다. 이를 블록이라고 한다. 블록 안에 변수가 선언되었다면 이를 지역변수라고 하고, 블록 밖에서 선언되었지만 블록 안에서 사용되는 변수라면 비지역변수라고 말한다. 전역 변수는 어떤 블록에도 포함되지 않는 곳에서 선언된 변수인데, 이 변수는 모든 블록에서 비지역변수이며 프로그램 전체에서 사용될 수 있다.
아래의 예시를 보면 변수 c 가 속한 블록 입장에서 바라볼 때, c는 지역변수이고 a와 b는 비지역변수이며 특히 a는 전역변수이다.

int a
{
	int b
    	{
        	int c
        }
}

타입

프로그램은 다양한 형태의 데이터를 처리하는데, 이를 효율적으로 수행하기 위해 타입이라는 개념이 필요하다. 타입은 데이터 집합과 연산의 집합을 함께 일컫는다. 예를 들면, 정수형 타입이라고 했을 때 데이터 집합은 -2, -1, 0, 1, 2와 같은 정수형이 있고 연산 집합으로는 +, - 등이 있을 것이다.

타입이 중요한 이유는 연산의 안전성을 보장하기 위함이다. 우리가 예상한 결과대로 값을 나오게 하려면, 타입을 설정해야 한다. 예를 들어 7.5 + 6 이라는 수식을 계산할 때, 만약 결과값의 타입을 지정하지 않았다면 13이 나올 수도 있다. 우리가 원하는 값인 13.5가 나올 수 있도록, 결과값이 실수형이라는 것을 정의해두어야 한다.

하지만 타입 적용에도 유연하게 대처할 수 있도록 지원하는 언어들이 있다. 타입의 오류를 모두 검출하는 것을 강타입 언어라고 하고, 일부 타입 오류를 허용하는 것을 약타입 언어, 타입 선언문이 없으면서 타입이 계속 변경될 수 있는 것은 무타입언어라고 부른다.

타입의 종류에는 정수형, 실수형, 문자형, 논리형, 열거형, 배열, 구조체, 클래스 등이 있다.

1. 정수형
정수 데이터를 다루는 타입이다. int 외에도 short, long, long long 등 언어마다 지원하는 타입이 있다. 정수형 데이터는 사칙연산, 나머지연산, 비트연산(XOR, AND 등), 관계연산(>, >= 등)이 가능하다

2. 실수형
실수 데이터를 다루는 타입이다. 사칙연산, 관계연산이 가능하다. 대표적으로 float 형이 있다.

3. 문자형
문자 데이터를 다루는 타입이다. ASCII 코드나 유니코드 등으로 표현된다. 관계연산이 가능하며, 문자 코드 값이 숫자에 대응되기도 하여 사칙연산과 비트연산이 가능한 언어도 있다. 대표적으로 char 형이 있다.

4. 문자열형
문자열이란 문자들의 나열을 의미한다. 문자열을 표현할 때는 "" 으로 큰 따옴표를 사용하며, 문자를 표현할 때는 '' 작은 따옴표를 사용한다.

char str[] = "abc"


5. 논리형
참과 거짓으로 구성된 논리 데이터를 다루는 타입이다. 논리곱, 논리합, 논리부정 등의 연산이 가능하다. 대표적으로 bool 형이 있다.

5. 열거형
순서가 있는 집합의 데이터를 다루는 타입이다. C, C+의 enum 이 이에 해당한다. 집합 내 데이터들은 사용자들이 이름을 붙일 수 있지만, 컴퓨터는 0, 1, 2 등의 순번으로 인식한다. 관계연산이 가능하며 언어에 따라 사칙연산도 가능하다.

enum Cat {cheeze, white, black};


6. 배열
같은 타입의 데이터의 모음으로 구성된 타입이다. 배열은 1차, 2차 등 n차원의 배열로 구현이 가능하다. 배열의 각 데이터인 원소는 첨자(0부터 시작하는 숫자로, 첫 원소와의 상대적 위치)로 구분된다.

int arr[2][3] ={1, 2, 3, 4, 5, 6};


8. 연관배열
같은 타입의 데이터 모음이지만, 순서는 없는 모음으로 구성된 타입이다. 원소 간의 위치 관계는 의미 없으며, 키(key)와 값(value)을 갖는다. C++에서는 map으로 표현한다.

map<string, int> m;
m["bread"] = "scorn";
m["coffee"] = "latte";


9. 구조체
같거나 다른 타입의 데이터 모음으로 구성된 타입이다. C, C++에서는 struct로 표현한다.

struct cat
{
	char name;
    int birth;
    double weight;
}


10. 공용체
구조체와 비슷하나, 하나의 데이터 공간을 여러 개의 데이터들이 같이 사용하는 데이터들의 모음이다. C, C++에서는 union으로 표현한다.

11. 포인터형
특정 데이터가 저장되는 주소 그 자체를 데이터로 다루는 타입이다.C, C++에서는 * 를 붙인다.

12. 참조형
사용자가 지정하는 타입의 데이터가 저장된 주소 자체를 자신의 주소로 사용하는 타입이다. C, C++에서는 &을 붙인다.


명령어

특정 작업을 지시하는 단어를 말한다. 프로그램이 언어는 연산자와 명령어를 통해 수식과 문장을 구성한다.


수식

수식이란 값을 나타내는 표현을 말하며, 연산자와 피연산자로 구성된다. 연산자는 연산을 수행하는 함수이며, 피연산자는 연산의 대상이 되는 값을 의미한다. 대표적인 연산자의 종류는 아래와 같다.
1. 산술연산자: 산술 연산자는 기본적으로 사칙 연산자를 의미한다.
2. 관계연산자: 2개의 피연산자를 서로 비교하여 >, <, >=, == 등으로 값을 비교하여 참과 거짓으로 나타낸다.
3. 논리연산자: 논리곱, 논리합, 부정 등이 있으며 참과 거짓으로 나타낸다.


문장

문장은 처리를 나타내는 표현을 말한다. 여기서 처리란, 값을 계산하는 것 혹은 수행 흐름을 바꾸는 것 등을 말한다. 문장의 종류는 선언문과 실행문이 있다.

1. 선언문
변수나 서브프로그램을 이용할 수 있도록 준비하는 것이다. 변수를 선언할 때는 변수명, 타입 등을 작성해야하고 서브 프로그램을 선언할 때는 서브프로그램의 프로토콜을 명시한다. 프로토콜이란 인자가 무엇이고, 인자는 어떤 타입이고, 인자는 몇 개이며, 반환해야하는 타입은 무엇인지 정의하는 것이다. 프로토콜만으로는 구체적으로 어떤 작업을 해야하는지 알지 못하므로, 작업은 미리 정의되어야 한다.

int x // 변수명은 x이며 타입은 int 이다
int add(int, int) // int 타입의 인자 2개로 add라는 작업을 수행하며 반환 타입은 int 이다

2. 실행문
변수, 서브프로그램 등을 이용하여 데이터를 처리하는 문장을 말한다.

1) 대입문
보통 = 라고 표현되는 대입문은, 수학의 등호와는 다르다. = 의 오른쪽 부분의 값을 왼쪽 변수에 값으로 대입할 떄 사용한다. 연산자와 함께 사용되어 간략하게 표기하기도 하는데, 예를 들어 a+=3은 a=a+3과 동일한 의미이다.

2) 제어문
제어문은 프로그램의 수행 흐름을 제어하는 것으로서, 조건문과 반복문이 있다.
조건문은 특정 조건에 맞추어 서로 다른 처리(분기처리)를 하도록 제어하는 것으로 if문, switch 문이 있다. if문은 조건이 참일 경우 then 다음의 문장을 수행하고, 조건이 거짓이라면 else 다음의 문장을 수행한다. swtich문은 조건의 값에 따라 모두 다르게 처리하여, 한 번에 여러 갈래로 흐름을 나눈다. if문과 switch문은 언어마다 표현 방법이 다를 수 있다.
반복문은 원하는 문장을 반복해서 수행하도록 제어하는 문장이다. for문, while문, do-while 문이 있다. for는 초기값에서부터 조건에 따라 반복수행한다. while은 조건이 참인 경우에 문장을 반복 수행하며, do-while은 while과 마찬가지이지만 반복횟수가 1번 이상이다.


서브프로그램

서브프로그램은 프로그램 조각이다. 서브프로그램과 같이 프로그램 일부를 가져다가 사용한다면(호출한다면), 코드의 중복을 줄일 수 있다. 서브프로그램이 호출되면 본 프로그램 실행 도중 서브프로그램으로 제어 흐름이 이전되며, 서브프로그램 내에서 출구를 만나면 서브프로그램은 종료되고 다시 본 프로그램으로 제어 흐름이 이동한다.

서브프로그램이 수행될 때 외부로부터 전달될 정보를 받는 인수를 형식인수(매개변수)라고 하며, 서브프로그램을 호출할 때 형식인수로 전달되는 값이나 주소를 실인수(인수)라고 부른다. 즉 호출한 프로그램의 실인수는 호출된 프로그램의 형식인수로 전달되는 것이다. 만약 실인수가 주어지지 않는 경우 기본값을 제공할 수 있는데 이를 기본인수라고 한다.

서브 프로그램의 과정을 살펴보면, 먼저 호출자는 서브프로그램을 만나면 호출자의 현재 상태를 저장해둔다. 이후 서브프로그램에게 인수를 전달하고, 서브프로그램이 끝났을 때 어디로 돌아오면 될지 주소를 저장한다. 이후 서브프로그램으로 이동하면, 형식인수는 값을 복사하고 반환해야하는 값이 있다면 값을 전달한다. 이후 저장해두었던 주소에 다시 찾아가서 복귀한다.

위 과정을 구현하기 위해서는 '활성 레코드'라는 것이 필요한데, 위 과정에 필요한 정보들을 저장해두는 것이다. 복귀해야하는 주소, 매개변수, 지역변수, 동적링크, 정적링크를 저장해둔다. 여기서 추가적으로 나오는 개념이 링크인데, 정적 링크는 현재 블록을 감싼 부모 블록의 주소(포인터)를 나타낸다. 동적 링크는 현재 블록(서브 프로그램)을 호출한 원래의 블록(호출자)의 주소(포인터)를 나타낸다.

서브프로그램의 종류로는, 수행 결과 값을 반환하는 함수와 결과 값을 반환하지 않는 프로시저가 있다. 용어가 헷갈려 정보통신기술용어해설에서 정의한 용어를 가져와보았다.
- 서브프로그램: 하나의 프로그램을 구성하는 여러 작은 단위의 프로그램들
- 서브루틴: 호출 시 명령문 만을 수행하고, 결과 값을 반환하지 않을 수 있음
- 함수: 여러 매개변수를 전달하면 함수는 결과에 대한 하나의 값만을 반환함
- 프로시저: 서브루틴과 유사하나, 계산과 규칙을 구체적으로 밝힌 것을 의미함


후기

 

 

프로그래밍 언어는 컴퓨터과학을 전공하는 이상 배워야하는 과목이다. 컴퓨터과학을 전공한 기획자들은 직접 코드를 읽어보기도 한다던데, 내가 직접 작성하지는 않더라도 언젠가는 소통할 때 필요할 수 있다고 생각하여 프로그래밍 언어를 하나씩 배우고 있다.

스티브 잡스는 "이 나라의 모든 사람은 프로그래밍을 배워야 합니다. 코딩은 생각하는 방법을 가르쳐 줍니다."라는 말을 남겼다고 한다. 컴퓨터는 논리적으로 명령을 처리하기 때문에, 프로그래밍 언어를 배운다는 것은 논리적인 사고를 배울 수 있는 길이라는 생각도 든다. 프로그래밍 언어론은 언어의 역사부터 시작하여, 패러다임, 보편적인 언어의 구성요소 등을 다루고 있기 때문에 언어를 배우기 위해 배경지식으로 알아두면 좋은 내용들이 많았다.

 

도움 받은 글

1. 방송통신대학교 컴퓨터과학과 강의록
2. 프로그래밍 코딩 왜 학습해야 할까, 코딩월드뉴스, https://www.codingworldnews.com/news/articleView.html?idxno=3709

3. 롤러코스터 타이쿤 시리즈, 나무위키, https://namu.wiki/w/롤러코스터%타이쿤%20시리즈%EF%BB%BF

4. 인터프리터, 나무위키,
https://namu.wiki/w/%EC%9D%B8%ED%84%B0%ED%94%84%EB%A6%AC%ED%84%B0

5. 컴파일러는 어떻게 내가 작성한 코드를 인식하는걸까? https://wormwlrm.github.io/2021/04/18/Formal-Language-and-Compiler.html

6. 프로그래밍 언어, 컴파일러, 인터프리터, https://imasoftwareengineer.tistory.com/43

7.객체지향 프로그래밍, 위키백과, https://ko.wikipedia.com/wiki/객체_지향_프로그래밍

8. 파스트리, 위키백과, https://ko.wikipedia.org/wiki/%ED%8C%8C%EC%8A%A4_%ED%8A%B8%EB%A6%AC

9. 메모리의 구조, http://www.tcpschool.com/c/c_memory_structure

10. 패러다임, 위키백과, https://ko.wikipedia.org/wiki/%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84

 

 

 

728x90

댓글