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

기술노트
(컴퓨터 과학 용어 정리 - C언어 컴파일 과정 추가)
 
편집 요약 없음
태그: 되돌려진 기여
1번째 줄: 1번째 줄:
==== C언어 컴파일 과정 ====
==== C 언어 컴파일 과정 ====


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


gcc를 통해 C언어로 작성된 코드가 컴파일되는 과정을 알아보자
<br>
 
[[파일:Compile-process.png|center|600px]]
 
위와 같은 단계를 통해 생성된 실행 파일은 메모리(RAM)에 적재되어 운영체제 상에서 실제로 동작하게 됩니다.


<br>
<br>


<img src="https://t1.daumcdn.net/cfile/tistory/254DB03A58326E501C">
=== 1. 전처리 (Preprocessing) ===
 
- `#include` 지시문에 따라 헤더 파일의 내용을 삽입합니다.
- `#define`, `#ifdef`, `#ifndef` 등 매크로를 해석하고 코드에 적용합니다.
- 주석 제거 및 조건부 컴파일 처리도 이 과정에서 수행됩니다.


이러한 과정을 거치면서, 결과물은 컴퓨터가 이해할 수 있는 바이너리 파일로 만들어진다. 이 파일을 실행하면 주기억장치(RAM)로 적재되어 시스템에서 동작하게 되는 것이다.
→ 전처리 결과는 확장자가 `.i`인 중간 코드로 저장됩니다.


<br>
<br>


1. #### 전처리 과정
=== 2. 컴파일 (Compilation) ===
 
전처리된 코드를 기반으로 어셈블리 코드로 변환하는 단계이며, 내부적으로는 세부적인 세 단계로 구성됩니다:
 
* '''전단부 (Front-end)''': 
  - 어휘 분석(Lexical Analysis), 구문 분석(Syntax Analysis), 의미 분석(Semantic Analysis)을 수행합니다. 
  - 주로 문법 오류를 탐지하는 역할을 합니다.


  - 헤더파일 삽입 (#include 구문을 만나면 헤더파일을 찾아 그 내용을 순차적으로 삽입)
* '''중단부 (Middle-end)''': 
  - 매크로 치환 및 적용 (#define, #ifdef와 같은 전처리기 매크로 치환 및 처리)
  - SSA(Static Single Assignment) 형태로 변환 후 다양한 최적화를 수행합니다. 
  - 실행 성능을 개선하기 위한 중간 코드 최적화가 이루어집니다.


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


2. #### 컴파일 과정 (전단부 - 중단부 - 후단부)
→ 결과는 `.s` 확장자의 어셈블리 코드 파일입니다.


  - '''전단부''' (언어 종속적인 부분 처리 - 어휘, 구문, 의미 분석)
<br>
  - '''중단부''' (SSA 기반으로 최적화 수행 - 프로그램 수행 속도 향상으로 성능 높이기 위함)
  - '''후단부''' (RTS로 아키텍처 최적화 수행 - 더 효율적인 명령어로 대체해서 성능 높이기 위함)


  <br>
=== 3. 어셈블 (Assembling) ===


3. #### 어셈블 과정
어셈블리 코드를 기계어(Object Code)로 번역하는 단계입니다.


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


  - 어셈블러로 생성되는 파일은 명령어와 데이터가 들어있는 ELF 바이너리 포맷 구조를 가짐
<br>
    (링커가 여러 바이너리 파일을 하나의 실행 파일로 효과적으로 묶기 위해 `명령어와 데이터 범위`를 일정한 규칙을 갖고 형식화 해놓음)


  <br>
=== 4. 링킹 (Linking) ===


4. #### 링킹 과정
- 여러 개의 오브젝트 파일(.o)과 라이브러리(.lib/.a)를 결합하여 하나의 실행 파일을 만듭니다.
- 함수 호출, 전역 변수 참조 등 서로 연결되지 않은 심볼(Symbol)을 해결합니다.
- 동적 라이브러리를 사용하는 경우 해당 정보를 실행 파일에 포함시킵니다.
 
→ 최종 결과물은 확장자가 `.out`, `.exe`, 또는 사용자 정의 이름의 실행 파일입니다.
 
<br>
 
== 요약 ==
 
{| class="wikitable"
|-
! 단계 !! 입력 파일 !! 출력 파일 !! 주요 도구
|-
| 전처리 || hello.c || hello.i || cpp
|-
| 컴파일 || hello.i || hello.s || cc1
|-
| 어셈블 || hello.s || hello.o || as
|-
| 링킹 || hello.o || a.out (또는 지정 이름) || ld
|}
 
<br>


  > 오브젝트 파일들과 프로그램에서 사용된 C 라이브러리를 링크함
== 관련 링크 ==
  >
  > 해당 링킹 과정을 거치면 실행파일이 드디어 만들어짐


  <br>
* [GCC 공식 문서](https://gcc.gnu.org/)
* [ELF 포맷 위키백과](https://ko.wikipedia.org/wiki/실행_가능_및_연결_형식)

2025년 4월 21일 (월) 13:59 판

C 언어 컴파일 과정

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


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


1. 전처리 (Preprocessing)

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

→ 전처리 결과는 확장자가 `.i`인 중간 코드로 저장됩니다.


2. 컴파일 (Compilation)

전처리된 코드를 기반으로 어셈블리 코드로 변환하는 단계이며, 내부적으로는 세부적인 세 단계로 구성됩니다:

  • 전단부 (Front-end):
 - 어휘 분석(Lexical Analysis), 구문 분석(Syntax Analysis), 의미 분석(Semantic Analysis)을 수행합니다.  
 - 주로 문법 오류를 탐지하는 역할을 합니다.
  • 중단부 (Middle-end):
 - SSA(Static Single Assignment) 형태로 변환 후 다양한 최적화를 수행합니다.  
 - 실행 성능을 개선하기 위한 중간 코드 최적화가 이루어집니다.
  • 후단부 (Back-end):
 - 대상 시스템 아키텍처에 맞게 최적화된 어셈블리 코드로 변환합니다.  
 - 불필요한 연산 제거, 명령어 재배치 등을 통해 실행 효율을 극대화합니다.

→ 결과는 `.s` 확장자의 어셈블리 코드 파일입니다.


3. 어셈블 (Assembling)

어셈블리 코드를 기계어(Object Code)로 번역하는 단계입니다.

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


4. 링킹 (Linking)

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

→ 최종 결과물은 확장자가 `.out`, `.exe`, 또는 사용자 정의 이름의 실행 파일입니다.


요약

단계 입력 파일 출력 파일 주요 도구
전처리 hello.c hello.i cpp
컴파일 hello.i hello.s cc1
어셈블 hello.s hello.o as
링킹 hello.o a.out (또는 지정 이름) ld


관련 링크