컴파일이란 무엇인가?
컴파일은 간단하다.
컴퓨터는 자연어(사람들이 쓰는 언어)를 알아듣지 못한다.
정확히 말하면, 컴퓨터는 0과 1로 이루어진 기계어만 이해할 수 있다.
하지만 개발자는 사람이 이해하기 쉬운 고급 언어(C, C++)로 코드를 작성한다.
이 둘 사이에는 명확한 간극이 존재한다.
이 간극을 메워주는 과정이 바로 컴파일이다.
컴파일이란,
개발자가 작성한 고급 언어 코드를
컴퓨터가 이해할 수 있는 저급 언어(기계어)로 번역하는 과정을 의미한다.
다음과 같은 코드를 예시로 들어보자.
std::string Name = "Shy";
int Age = 25;
bool Gender = true;
std::cout << "Hello" << std::endl;
std::cout << Name << std::endl;
std::cout << Age << std::endl;
if(Gender == true)
{
std::cout << "남자" << std::endl;
}
else
{
std::cout << "여자" << std::endl;
}
이 코드는 매우 직관적인 코드이다.
- 이름은 "Shy"이다.
- 나이는 25살이다.
- 성별은 "남자"이다.
하지만 컴퓨터 입장에서는 이와 직관적인 코드도 이해할 수 없다.
개발자 입장에서 위와 같은 고급 언어는 다음 문장과 같이 읽을 수 있다.
안녕하세요. 제 이름은 Shy이고, 나이는 25살입니다.
참고로 성별은 남자입니다.
그렇다면 컴퓨터에게도 이와 같이 보일까?
아니다.
지금부터 컴퓨터에게 어떻게 보일지 직관적인 예시로 보여주겠다.
χαίρετε. τὸ ὄνομά μοι ἐστὶ Σάι, καὶ εἴκοσι καὶ πέντε ἐτῶν εἰμί.
ἄρρην δέ εἰμι.
이것이 컴퓨터 입장에서 보이는 고급 언어의 모습이다.
당신은 이게 무엇인지 아는가?
놀랍게도 위의 문장을 고대 그리스어를 번역한 것이다.
이 문장을 보고 당신은 무슨 생각을 했는가?
이 문장을 이해했는가? 아니면 이 문장이 무엇인지 짐작도 하지 못했는가?
사람도 자신이 사용하지 않던 언어를 접하게 되면, 의사소통이 원활히 이루어지지 않는다.
컴퓨터도 똑같다.
이들은 자신이 배워보지 못한 언어를 처음 접하게 되서 개발자의 의도를 알아차리지 못한다.
그럼 다시 저 그리스어를 보면서 생각해보자. 우리는 모르는 언어를 처음 접하게 되면 무엇을 생각하는가?
바로 자신이 사용하는 언어로 번역을 하고자 한다.
이것은 내가 사용하는 언어로 번역하면 어떻게 표기하는가? 어떻게 발음하는가?
그렇게 번역된 내용을 읽거나 듣고서 우리는 그들이 전하고자 했던 말을 비로소 이해할 수 있게 된다.
컴퓨터도 똑같다.
그들은 우리가 전달하는 고급 언어를 자신이 이해할 수 있는 기계어로 번역하고자 한다.
그것이 바로 컴파일이다.
컴파일의 정의를 이해했다면, 다음으로 자연스럽게 떠오르는 질문은 다음과 같을 것이다.
그렇다면,
우리는 컴파일이란 기능을 언제 사용하는가?
그리고 컴파일을 사용함으로써
우리는 무엇을 얻고자 하는가?
컴파일은 언제 사용되는가?
1. 소스 코드에 문법적 오류가 있는지 확인할 때
컴파일은 과정에서는 다음과 같은 오류들이 자동으로 검출된다
- 문법 오류 (세미콜론 누락, 괄호 불일치 등)
- 타입 오류 (자료형 불일치)
- 선언되지 않은 변수나 함수 사용
- 함수 시그니처 불일치
즉, 컴파일은 "이 코드가 실행 가능한 형태인가?"를 1차적으로 검증하는 역할을 한다.
이 단계에서 오류가 발생하면, 프로그램은 실행조차 할 수 없다.
단, 알고리즘 오류는 잡을 수 없어서 직접 검증을 마쳐야 한다.
2. 내가 구현한 기능을 실제로 실행해 보고 싶을 때
내가 작성한 소스 코드는 컴파일이 완료되어야만 실행이 가능하다.
따라서,
- 내가 작성한 함수의 동작 여부
- 알고리즘 오류 확인
등을 확인하기 위해 반드시
컴파일 → 실행 과정을 거쳐야 한다.
(컴파일은 기능 검증을 위한 전제 조건이다.)
3. 실행 속도와 성능이 중요한 프로그램을 만들 때
컴파일된 코드는 실행 전에 기계어로 변환되기 때문에,
- 실행 중 해석 과정이 없다.
- CPU가 바로 실행할 수 있다.
그래서 다음과 같은 상황에서 컴파일 방식이 선택된다.
- 게임 엔진
- 서버 프로그램
- 그래픽, 물리 연산
- 실시간 처리가 필요한 시스템
4. 시스템 자원을 직접 제어해야 할 때
컴파일 언어는
- 메모리 구조
- 하드웨어 접근
- 저수준 제어
에 유리하다.
따라서 운영체제, 드라이버, 임베디드 시스템처럼 하드웨어와 가까운 작업이 필요한 경우 컴파일 방식이 필수적이다.
그렇다면 컴파일을 통해 얻을 수 있는 장점은?
<실행 성능>
- 실행 속도가 빠르다.
- 자원 사용이 효율적이다
<사전 오류 검출>
- 문법, 타입 오류를 실행 전에 발견할 수 있다.
- 프로그램의 안정성이 향상된다.
<배포 안정성>
- 실행 파일만 배포가 가능하다.
- 소스 코드의 노출이 최소화된다.
<대교무 프로젝트에 적합>
- 컴파일러 최적화
- 정적 분석 가능
컴파일의 한계 (단점)
<개발 속도 저하>
- 코드 수정 시마다 재컴파일 필요
- 컴파일 시간이 길어질 수 있음
<플랫폼 종속성>
- 운영체제, 아키텍처에 따라 재컴파일 필요
<즉각적인 테스트에 불리함>
- 인터프리터 언어처럼 즉시 실행이 불가능
