프로그래밍웹 교과서
이 페이지의 목차
1단원 · 2차시

번역 방식으로 나눠 보는 언어 — 컴파일러와 인터프리터

컴파일러인터프리터하이브리드목적 코드바이트 코드

코드 예제: Python · C · 예상 50분

학습 목표

  • 컴파일러와 인터프리터의 번역 방식 차이를 설명한다.
  • 같은 문제를 두 방식의 언어로 실행할 때의 차이를 비교한다.

관련 성취기준

  • 프그01-01

    각종 프로그래밍 언어의 종류와 특징을 이해하고, 개발 분야와 용도에 따라 적절한 프로그래밍 언어를 선택할 수 있다.

생각 열기 — 번역가와 통역사

외국어로 된 책을 읽어야 한다. 방법은 두 가지다.

하나는 번역가에게 책 전체를 맡기는 것이다. 시간이 걸리지만 한 번 끝내 두면 한국어 책이 남는다. 그 뒤로는 번역가 없이 몇 번이든 읽을 수 있고, 읽는 속도도 빠르다.

다른 하나는 통역사를 옆에 두는 것이다. 한 문장 읽을 때마다 그 자리에서 옮겨 준다. 기다릴 필요 없이 바로 시작할 수 있다. 그러나 읽는 동안 통역사가 계속 옆에 있어야 하고, 같은 책을 다시 읽을 때도 처음부터 다시 옮겨야 한다.

고급 언어는 반드시 번역된다

1차시에서 확인한 대로 중앙처리장치가 실행할 수 있는 것은 기계어뿐이다. Python이든 C든 고급 언어로 쓴 코드는 그대로 실행되지 않는다. 기계어로 옮기는 단계를 반드시 거친다.

빈칸 채우기번역 방식을 한 문장으로

실행하기 전에 소스 코드 전체를 미리 기계어로 옮겨 두는 방식을 1이라 하고, 실행하면서 한 줄씩 그때그때 옮기는 방식을 2이라 한다.

정답 보기
  1. 컴파일
  2. 해석

옮기는 방식은 앞의 번역가와 통역사처럼 두 갈래로 나뉜다. 실행하기 전에 전체를 미리 옮겨 두는 방식이 컴파일이고, 실행하면서 필요한 만큼 그때그때 옮기는 방식이 해석이다.

컴파일 방식 — 실행 전에 전부 번역해 실행 파일을 만든다소스 코드컴파일러목적 코드링커실행 파일실행 파일만 있으면 소스 코드도 컴파일러도 없이 돌아간다.인터프리터 방식 — 실행하면서 한 줄씩 번역한다소스 코드인터프리터한 줄 실행 · 결과다음 줄로 넘어가같은 일을 되풀이한다.
같은 소스 코드가 실행에 이르는 두 갈래 경로. 위는 컴파일 방식, 아래는 인터프리터 방식이다.자체 제작

컴파일러 — 미리 전부 번역한다

컴파일러(compiler) — 소스 코드 전체를 실행 전에 한 번에 번역하는 프로그램는 소스 코드 전체를 훑어 기계어로 옮긴다. 그 결과로 나오는 것이 목적 코드(object code) — 기계어로 번역됐지만 아직 혼자 실행되지는 못하는 중간 결과물다.

목적 코드는 아직 혼자 실행되지 못한다. 프로그램이 쓰는 화면 출력 기능처럼 미리 만들어져 있는 부분과 이어 붙여야 하기 때문이다. 여러 목적 코드와 라이브러리를 하나로 묶어 실행 파일을 만드는 일을 링커(linker) — 목적 코드와 라이브러리를 묶어 실행 파일로 만드는 프로그램가 한다.

이 과정이 끝나면 실행 파일 하나가 남는다. 소스 코드도 컴파일러도 필요 없다. 우리가 내려받아 쓰는 프로그램 대부분이 이렇게 만들어진 실행 파일이다. C가 대표적인 컴파일 방식 언어다.

인터프리터 — 한 줄씩 그때그때 번역한다

인터프리터(interpreter) — 소스 코드를 실행하면서 한 줄씩 번역해 곧바로 수행하는 프로그램는 실행 파일을 만들지 않는다. 소스 코드를 위에서부터 읽어 한 줄을 번역하고 곧바로 실행한 뒤 다음 줄로 넘어간다.

그래서 코드를 고치고 바로 실행해 결과를 볼 수 있다. 대신 프로그램을 실행하려면 소스 코드와 인터프리터가 늘 함께 있어야 한다. 번역과 실행을 같이 하므로 같은 계산이라면 실행 파일보다 느리다. Python이 대표적인 인터프리터 방식 언어다.

순서 맞추기컴파일 방식에서 실행 파일이 만들어지기까지
  1. 1소스 코드
  2. 2컴파일러가 번역
  3. 3목적 코드
  4. 4링커가 묶음
  5. 5실행 파일

언제 오류를 만나는가

두 방식의 차이가 가장 뚜렷하게 드러나는 곳이 오류를 만나는 시점이다. 같은 실수를 두 언어에 심어 보자. 세 줄을 출력하는 프로그램인데 마지막 줄에서 print를 prnit로 잘못 적었다.

예상해 보기

세 줄을 출력하는 코드인데 셋째 줄에 오타가 있다. Python으로 실행하면 화면에 어디까지 찍힐까?

결과 바로 보기
첫째 줄
둘째 줄
Python셋째 줄에 오타가 있는 Python 코드
print("첫째 줄")
print("둘째 줄")
prnit("셋째 줄")
확인된 실행 결과
첫째 줄
둘째 줄

브라우저에서 실행되지 않는 예제다. 일부러 오류를 내는 예제다. 표준 출력만 적었고, 그 뒤에 오류 메시지가 따라 나온다. 전산실 컴파일러에 붙여 넣어 확인해 보자.

앞의 두 줄은 출력됐다. 그리고 세 번째 줄에서 멈추며 NameError: name 'prnit' is not defined 라는 오류가 나온다. 인터프리터는 첫 줄부터 차례로 번역해 실행하므로, 세 번째 줄에 닿기 전까지는 오타가 있다는 사실 자체를 모른다.

C같은 오타를 넣은 C 코드확인된 출력
#include <stdio.h>

int main(void)
{
    printf("첫째 줄\n");
    printf("둘째 줄\n");
    prntf("셋째 줄\n");
    return 0;
}
실행 결과
(화면에 출력되는 내용 없음)

브라우저에서 실행되지 않는 예제다. 일부러 컴파일이 실패하는 예제다. 실행 파일이 만들어지지 않으므로 출력이 없다. 전산실 컴파일러에 붙여 넣어 확인해 보자.

C는 아무것도 출력하지 않는다. 컴파일러가 소스 코드 전체를 먼저 훑어 일곱째 줄의 오타를 찾아내고, call to undeclared function 'prntf' 라는 메시지를 낸 뒤 실행 파일을 만들지 않는다. 앞의 두 줄은 옳게 적혀 있지만 실행될 기회가 없다.

같은 계산을 두 언어로

1부터 10까지 더하는 프로그램을 두 언어로 적었다. 상단의 언어 단추로 바꿔 볼 수 있다.

Python1부터 10까지의 합
total = 0
for i in range(1, 11):
    total += i
print("1부터 10까지의 합:", total)
확인된 실행 결과
1부터 10까지의 합: 55
C1부터 10까지의 합확인된 출력
#include <stdio.h>

int main(void)
{
    int total = 0;
    for (int i = 1; i <= 10; i++) {
        total += i;
    }
    printf("1부터 10까지의 합: %d\n", total);
    return 0;
}
실행 결과
1부터 10까지의 합: 55

결과는 같은 55다. 다른 것은 그 결과에 이르는 길이다. Python 코드는 저장하고 곧바로 실행했다. C 코드는 컴파일해 실행 파일을 만든 뒤 그 파일을 실행했다. 문법의 차이는 2단원에서 하나씩 다룬다.

두 방식을 섞은 하이브리드

컴파일과 해석은 서로 배타적이지 않다. 둘을 섞은 하이브리드 방식(hybrid) — 소스 코드를 중간 형태로 컴파일한 뒤 그것을 해석해 실행하는 방식도 널리 쓰인다.

Java가 대표적이다. Java 컴파일러는 소스 코드를 특정 중앙처리장치의 기계어가 아니라 바이트 코드(byte code) — 특정 중앙처리장치가 아니라 가상 머신이 해석하도록 만든 중간 코드로 번역한다. 그 바이트 코드를 가상 머신(virtual machine) — 바이트 코드를 해석해 실제 기계에서 실행해 주는 프로그램이 해석해 실행한다. 한 번 컴파일한 바이트 코드를 가상 머신이 있는 어느 기종에서나 쓸 수 있다는 것이 이 방식의 이점이다.

두 방식을 갈라 보기

분류하기컴파일 방식인가 인터프리터 방식인가

카드를 누른 뒤, 넣을 통을 누른다. 통 안의 카드를 누르면 다시 나온다.

컴파일 방식

인터프리터 방식

정리

컴파일 방식과 인터프리터 방식의 비교
기준컴파일 방식인터프리터 방식
번역 시점실행 전에 전체를 한 번에실행하면서 한 줄씩
남는 산출물목적 코드와 실행 파일없다
실행 속도빠르다상대적으로 느리다
문법 오류를 만나는 때실행 전 컴파일 단계그 줄에 닿았을 때
코드를 고친 뒤다시 컴파일해야 한다바로 실행한다
실행에 필요한 것실행 파일만소스 코드와 인터프리터
다른 기종으로 옮기기기종마다 다시 컴파일한다인터프리터만 있으면 된다
대표 언어C, C++Python, JavaScript

활동

실습

같은 코드를 두 방식으로 실행해 차이 관찰하기

약 15분
  1. 위의 합 구하기 Python 코드를 실행해 결과를 확인한다.
  2. 같은 일을 하는 C 코드를 전산실 컴파일러로 컴파일해 실행한다. 컴파일 명령과 실행 명령이 따로 있다는 점을 확인한다.
  3. 두 코드에서 각각 한 글자만 일부러 지운다. Python은 range 의 괄호 하나, C는 문장 끝 세미콜론 하나를 지워 보자.
  4. 오류 메시지가 언제 나왔는지 기록한다. 실행하기 전인가, 실행 중인가.
  5. 표로 정리한다 — 지운 것 / 오류가 난 시점 / 오류 메시지 / 앞부분이 실행됐는가.

3번에서 지운 글자는 반드시 되돌려 놓는다.

개념 확인 문제

보기를 누르면 바로 채점된다. 틀려도 해설을 읽으면 된다.

컴파일러와 인터프리터의 가장 큰 차이는 무엇인가?프그01-01

본문의 오타 예제에서 C 코드가 첫째 줄조차 출력하지 못한 이유는?프그01-01

[OX] C로 컴파일해 만든 실행 파일은 종류가 다른 중앙처리장치에서도 그대로 실행된다.프그01-01

Java의 실행 방식을 바르게 설명한 것은?프그01-01

더 알아보기

심화느린 인터프리터를 빠르게 — JIT 컴파일

인터프리터 방식의 약점은 속도다. 같은 반복문을 수만 번 돌 때, 그 안의 코드를 매번 다시 번역하는 것은 낭비다. 그래서 자주 실행되는 부분만 실행 중에 기계어로 컴파일해 두고 다음부터는 그것을 쓰는 방법이 나왔다. 실행하는 그때 컴파일하므로 적시 컴파일(JIT, Just-In-Time compilation)이라 한다. 오늘날 웹 브라우저의 JavaScript 실행기와 Java 가상 머신이 이 방법을 쓴다.

인물최초의 컴파일러를 만든 그레이스 호퍼

1952년, 미국의 수학자이자 해군 장교였던 그레이스 호퍼는 사람이 읽을 수 있는 기호로 적은 코드를 기계어로 바꿔 주는 프로그램 A-0를 만들었다. 최초의 컴파일러로 평가받는다. 당시에는 “컴퓨터에게 영어에 가까운 말로 지시한다”는 생각 자체가 받아들여지지 않았다고 한다. 그가 참여한 COBOL은 이후 수십 년간 금융·행정 업무 프로그램의 표준이 되었다.

실무컴파일 오류와 실행 오류는 다른 것이다

컴파일 단계에서 걸리는 것은 문법이 어긋난 코드다. 괄호가 안 닫혔거나 없는 이름을 불렀거나 자료형이 맞지 않는 경우다. 그런데 문법이 완벽해도 계산이 틀리거나 프로그램이 중간에 멈추는 일은 얼마든지 있다. 0으로 나누기, 없는 파일 열기, 조건을 거꾸로 쓴 경우가 그렇다. 이런 것은 컴파일러가 잡아 주지 못하고 실행해 봐야 드러난다. 그래서 컴파일 성공은 출발점일 뿐이며, 5차시에서 다루는 테스트가 필요하다.

이어지는 학습

이 차시를 이해하려면 다음을 먼저 알아야 한다.

  • 1차시의 저급 언어와 고급 언어 구분 — 프로그래밍 프그01-01

교과서에서 찾기

교과서해당 위치쪽수
성림출판(Python)프로그래밍의 개요 › 01 프로그래밍 언어의 종류와 특징12쪽
씨마스커뮤니케이션(Python)프로그래밍 개요 › 1 프로그래밍 언어의 종류와 특징14쪽
삼양미디어(Python)프로그래밍의 개요 › 01 프로그래밍 언어12쪽
삼양미디어(C)프로그래밍의 개요 › 01 프로그래밍 언어12쪽
씨마스(C)프로그래밍의 개요 › 1 프로그래밍 언어의 종류와 특징12쪽
웅보출판사(C)프로그래밍의 개요 › Chapter 01 프로그래밍 언어의 종류와 특징11쪽