C언어 컴파일 과정: 두 판 사이의 차이

기술노트
편집 요약 없음
태그: 되돌려진 기여 시각 편집
편집 요약 없음
 
(같은 사용자의 중간 판 3개는 보이지 않습니다)
1번째 줄: 1번째 줄:
==== C 언어 컴파일 과정 ====
==== C언어 컴파일 과정 ====


C 언어로 작성된 소스 코드는 여러 단계를 거쳐 컴퓨터가 이해할 수 있는 실행 가능한 바이너리 파일로 변환됩니다. 이 과정은 일반적으로 다음과 같은 4단계로 나뉘며, 대표적인 컴파일러인 `gcc`를 기준으로 설명합니다.
C언어로 작성된 소스 코드가 실제 실행 가능한 프로그램이 되기까지 과정을 알아보자.<br>


[[파일:Compilation_process.png|center|500px]]


위와 같은 단계를 통해 생성된 실행 파일은 메모리(RAM)에 적재되어 운영체제 상에서 실제로 동작하게 됩니다.


<br>


=== 1. 전처리 (Preprocessing) ===
이러한 일련의 과정을 거치면서 '''결과물은 컴퓨터가 이해할 수 있는 바이너리 파일'''로 만들어진다. 
 
이 바이너리 파일은 메모리(RAM)에 적재되어 시스템에서 실행된다.
 
=== 1. 전처리(Preprocessing) 과정 ===
 
전처리기는 소스 코드를 컴파일하기 전에 '''코드를 확장하고 정리하는 작업'''을 한다.


- `#include` 지시문에 따라 헤더 파일의 내용을 삽입합니다.
* `#include` 구문을 만나면, 헤더 파일의 내용을 소스 코드에 그대로 삽입한다.
- `#define`, `#ifdef`, `#ifndef` 등 매크로를 해석하고 코드에 적용합니다.
* `#define`, `#ifdef` 등 매크로 명령어를 처리하거나 조건부 컴파일을 수행한다.
- 주석 제거 및 조건부 컴파일 처리도 이 과정에서 수행됩니다.


전처리 결과는 확장자가 `.i`인 중간 코드로 저장됩니다.
'''완성된 소스 코드가 준비되는 단계'''이다.<br>


<br>
=== 2. 컴파일(Compilation) 과정 ===


=== 2. 컴파일 (Compilation) ===
전처리가 끝난 소스 파일을 '''기계어로 변환하기 위한 중간 코드'''로 바꾸는 과정이다.


전처리된 코드를 기반으로 어셈블리 코드로 변환하는 단계이며, 내부적으로는 세부적인 세 단계로 구성됩니다:
보통 컴파일 과정은 내부적으로 세 단계로 나뉜다.


* '''전단부 (Front-end)''':   
* '''전단부 (Front-end)''':   
   - 어휘 분석(Lexical Analysis), 구문 분석(Syntax Analysis), 의미 분석(Semantic Analysis)을 수행합니다. 
   - 문법 검사 (어휘 분석, 구문 분석, 의미 분석)
   - 주로 문법 오류를 탐지하는 역할을 합니다.
   - 오류가 있을 경우 이 단계에서 컴파일 에러 발생


* '''중단부 (Middle-end)''':   
* '''중단부 (Middle-end)''':   
   - SSA(Static Single Assignment) 형태로 변환 후 다양한 최적화를 수행합니다.  
   - 프로그램을 최적화 (SSA 기반 최적화)   
   - 실행 성능을 개선하기 위한 중간 코드 최적화가 이루어집니다.
   - 코드 실행 속도를 빠르게 하기 위해 불필요한 연산 제거 등 처리


* '''후단부 (Back-end)''':   
* '''후단부 (Back-end)''':   
   - 대상 시스템 아키텍처에 맞게 최적화된 어셈블리 코드로 변환합니다.  
   - 타겟 CPU 구조에 맞춰 아키텍처 최적화  
   - 불필요한 연산 제거, 명령어 재배치 등을 통해 실행 효율을 극대화합니다.
   - 실제 명령어 세트로 변환 (x86, ARM 등)


결과는 `.s` 확장자의 어셈블리 코드 파일입니다.
이 과정을 거쳐 '''어셈블리 코드'''가 생성된다.


<br>
=== 3. 어셈블(Assembling) 과정 ===
 
* 어셈블러(Assembler)가 어셈블리 코드를 읽어 '''기계어(Object 파일)'''로 변환한다.
* 생성된 오브젝트 파일은 보통 '''ELF 포맷'''(Executable and Linkable Format) 구조를 가진다.
 
> ELF 포맷: 


=== 3. 어셈블 (Assembling) ===
> - 명령어 코드 영역과 데이터 영역을 명확하게 구분해 놓은 파일 구조 


어셈블리 코드를 기계어(Object Code)로 번역하는 단계입니다.
> - 나중에 링커가 여러 오브젝트 파일을 쉽게 연결할 수 있게 도와준다.


- 어셈블러는 `.s` 파일을 받아 `.o` 확장자의 오브젝트 파일(Object File)로 변환합니다.
=== 4. 링킹(Linking) 과정 ===
- 생성된 오브젝트 파일은 **ELF(Executable and Linkable Format)** 구조를 따르며, 명령어와 데이터가 일정한 규칙으로 정렬되어 있습니다.
- 이 구조는 나중에 링커가 여러 오브젝트 파일과 라이브러리를 효과적으로 결합할 수 있도록 돕습니다.


<br>
* 여러 오브젝트 파일(.o)과 프로그램에서 사용된 라이브러리 파일을 '''하나로 묶는 작업'''이다.
* 링커가 심볼(함수나 변수 이름)을 연결해서 최종 실행 파일을 만든다.


=== 4. 링킹 (Linking) ===
> 링킹 결과: 


- 여러 개의 오브젝트 파일(.o)과 라이브러리(.lib/.a)를 결합하여 하나의 실행 파일을 만듭니다.
> - 완성된 실행파일 (.out, .exe 등)이 만들어진다.
- 함수 호출, 전역 변수 참조 서로 연결되지 않은 심볼(Symbol)을 해결합니다.
- 동적 라이브러리를 사용하는 경우 해당 정보를 실행 파일에 포함시킵니다.


→ 최종 결과물은 확장자가 `.out`, `.exe`, 또는 사용자 정의 이름의 실행 파일입니다.
> - 이제 이 파일은 운영체제에서 실행할 수 있다.


<br>
<br>
60번째 줄: 66번째 줄:
== 요약 ==
== 요약 ==


{| class="wikitable"
* 전처리(Preprocessing): 소스 확장 및 정리
|-
* 컴파일(Compilation): 기계어로 변환 준비
! 단계 !! 입력 파일 !! 출력 파일 !! 주요 도구
* 어셈블(Assembling): 오브젝트 파일 생성
|-
* 링킹(Linking): 실행 파일 완성
| 전처리 || hello.c || hello.i || cpp
|-
| 컴파일 || hello.i || hello.s || cc1
|-
| 어셈블 || hello.s || hello.o || as
|-
| 링킹 || hello.o || a.out (또는 지정 이름) || ld
|}
 
<br>


== 관련 링크 ==
→ 이 4단계를 통해 '''C 프로그램은 실제로 동작하는 실행파일'''이 된다.


* [GCC 공식 문서](https://gcc.gnu.org/)
[[분류:프로그래밍]]
* [ELF 포맷 위키백과](https://ko.wikipedia.org/wiki/실행_가능_및_연결_형식)
[[분류:C 언어]]
[[분류:컴파일러]]

2025년 4월 26일 (토) 13:24 기준 최신판

C언어 컴파일 과정

C언어로 작성된 소스 코드가 실제 실행 가능한 프로그램이 되기까지 과정을 알아보자.

Compilation process.png


이러한 일련의 과정을 거치면서 결과물은 컴퓨터가 이해할 수 있는 바이너리 파일로 만들어진다.

이 바이너리 파일은 메모리(RAM)에 적재되어 시스템에서 실행된다.

1. 전처리(Preprocessing) 과정

전처리기는 소스 코드를 컴파일하기 전에 코드를 확장하고 정리하는 작업을 한다.

  • `#include` 구문을 만나면, 헤더 파일의 내용을 소스 코드에 그대로 삽입한다.
  • `#define`, `#ifdef` 등 매크로 명령어를 처리하거나 조건부 컴파일을 수행한다.

완성된 소스 코드가 준비되는 단계이다.

2. 컴파일(Compilation) 과정

전처리가 끝난 소스 파일을 기계어로 변환하기 위한 중간 코드로 바꾸는 과정이다.

보통 컴파일 과정은 내부적으로 세 단계로 나뉜다.

  • 전단부 (Front-end):
 - 문법 검사 (어휘 분석, 구문 분석, 의미 분석)
 - 오류가 있을 경우 이 단계에서 컴파일 에러 발생
  • 중단부 (Middle-end):
 - 프로그램을 최적화 (SSA 기반 최적화)  
 - 코드 실행 속도를 빠르게 하기 위해 불필요한 연산 제거 등 처리
  • 후단부 (Back-end):
 - 타겟 CPU 구조에 맞춰 아키텍처 최적화  
 - 실제 명령어 세트로 변환 (x86, ARM 등)

→ 이 과정을 거쳐 어셈블리 코드가 생성된다.

3. 어셈블(Assembling) 과정

  • 어셈블러(Assembler)가 어셈블리 코드를 읽어 기계어(Object 파일)로 변환한다.
  • 생성된 오브젝트 파일은 보통 ELF 포맷(Executable and Linkable Format) 구조를 가진다.

> ELF 포맷:

> - 명령어 코드 영역과 데이터 영역을 명확하게 구분해 놓은 파일 구조

> - 나중에 링커가 여러 오브젝트 파일을 쉽게 연결할 수 있게 도와준다.

4. 링킹(Linking) 과정

  • 여러 오브젝트 파일(.o)과 프로그램에서 사용된 라이브러리 파일을 하나로 묶는 작업이다.
  • 링커가 심볼(함수나 변수 이름)을 연결해서 최종 실행 파일을 만든다.

> 링킹 결과:

> - 완성된 실행파일 (.out, .exe 등)이 만들어진다.

> - 이제 이 파일은 운영체제에서 실행할 수 있다.


요약

  • 전처리(Preprocessing): 소스 확장 및 정리
  • 컴파일(Compilation): 기계어로 변환 준비
  • 어셈블(Assembling): 오브젝트 파일 생성
  • 링킹(Linking): 실행 파일 완성

→ 이 4단계를 통해 C 프로그램은 실제로 동작하는 실행파일이 된다.