컴파일링이란
C 코드를 실행하려면 컴파일을 해야 한다. 텍스트 형식의 C 코드가 컴퓨터가 해석 가능한 파일로 변환되는 과정을 알아보자.
#include <stdio.h>
int main(void)
{
printf("hello, world\n");
}
- main 함수는 프로그램의 시작점이고, printf는 출력 함수다. printf를 사용하려면 stdio.h 라이브러리가 필요하다.
stdio.h는 C 언어로 작성된 헤더 파일로printf함수의 프로토타입을 가지고 있어,clang컴파일러가printf가 무엇인지 알 수 있게 한다.
$ clang hello.c
$ ./a.out
컴파일 결과 a.out이라는 실행 파일이 생성된다.
다른 이름으로 컴파일하려면 -o 옵션을 사용한다.
$ clang -o hello hello.c
CS50 라이브러리를 사용한다면 -lcs50 옵션을 추가한다.
$ clang -o hello hello.c -lcs50
make 명령어를 사용하면 이 과정들을 더 간단히 할 수 있다.
컴파일의 4단계
전처리 (Precompile)
전처리는 전처리기가 #으로 시작하는 명령을 처리하는 단계다.
#include는 다른 파일의 내용을 포함하라는 의미다. #include <stdio.h>가 있으면 전처리기는 stdio.h 파일의 내용을 해당 위치에 삽입한 새 파일을 생성한다. 이 파일은 여전히 C 소스 코드 형태다.
컴파일 (Compile)
컴파일은 C 코드를 어셈블리어로 변환하는 단계다.
어셈블리는 C보다 연산 종류가 훨씬 적지만, 여러 연산을 조합하면 C에서 할 수 있는 모든 것을 수행할 수 있다. 컴파일러는 C 코드를 컴퓨터가 이해할 수 있는 언어에 최대한 가까운 형태로 변환한다.
"컴파일"이라는 용어는 전체 변환 과정을 의미하기도 하지만, 구체적으로는 전처리된 소스 코드를 어셈블리 코드로 변환하는 이 단계를 가리킨다.
어셈블 (Assemble)
어셈블은 어셈블리 코드를 오브젝트 코드로 변환하는 단계다.
컴퓨터의 CPU가 이해할 수 있는 명령어 형태인 0과 1로 변환한다. 이 작업은 어셈블러가 수행한다.
파일이 하나뿐이라면 여기서 컴파일이 끝난다. 여러 파일이 있다면 링크 단계가 필요하다.
링크 (Link)
프로그램이 여러 파일로 이루어져 있다면 링크 단계가 필요하다.
링커는 여러 오브젝트 코드 파일을 실행 가능한 하나의 파일로 합친다. 예를 들어 CS50 라이브러리를 링크하면 get_int()나 get_string() 같은 함수를 실행할 수 있게 된다.
이 4단계를 거치면 최종적으로 실행 가능한 파일이 완성된다.
연습 문제
Q. 컴파일 과정 없이 바로 머신 코드로 프로그램을 작성한다면 어떤 문제가 있을까?
직접 머신 코드로 프로그램을 작성하는 것은 매우 복잡하고 시간이 많이 소요된다. 또한 유지보수와 디버깅이 극도로 어려워진다.
컴파일러가 있기 때문에 우리는 사람이 읽을 수 있는 고수준 언어로 작성하고, 컴퓨터가 실행할 수 있는 저수준 코드로 자동 변환할 수 있다.
'TIL' 카테고리의 다른 글
| [CS50] 배열 (0) | 2025.11.05 |
|---|---|
| [CS50] 디버깅 (0) | 2025.11.05 |
| [CS50] 하드웨어의 한계와 오버플로우 (0) | 2025.11.05 |
| [CS50] C 언어 - 사용자 정의 함수와 중첩루프 (0) | 2025.11.05 |
| [CS50] C 언어 - 자료형과 연산자 (0) | 2025.11.05 |
