C++ 컴파일 과정 - 전처리

NYH·2023년 11월 26일

C++

목록 보기
9/17

목차

  1. 컴파일 과정 요약
  2. 전처리
  3. 선언과 정의
    ?. 문제풀이


1. 컴파일 과정 요약

  1. 전처리 과정에서 #include 파일의 내용을 코드로 치환합니다. 또한 #define 부분을 코드로 치환합니다.

  2. 각 소스 코드들을 컴파일러가 어셈블리어로 읽을 수 있는 어셈블러 파일 *.s 파일로 변환합니다.

  3. 어셈블리어 파일을 컴파일러가 Object 코드로 변환합니다.

  4. 링크 과정을 통해 컴파일러가 생성한 Object 코드와 외부 라이브러리 파일들을 모아서 실행 파일을 생성합니다. ex) *.exe


2. 전처리

문자 해석

소스 파일에 있는 문자들을 해석하는 과정입니다.
기본적으로 c++ 코드에서 제공하는 96개의 문자들로 이루어진 Basic source character set이 존재합니다.

1. 대문자 알파벳 : 26개
2. 소문자 알파벳 : 26개
3. 숫자 (0 - 9)  : 10개
4. 특수문자 : 29개 

5. 공백문자 : 5개 (특수문자에 포함됨)
스페이스 (Space): ''
수평 탭 (Horizontal Tab): '\t'
새 줄 (Newline): '\n'
캐리지 리턴 (Carriage Return): '\r'
수직 탭 (Vertical Tab): '\v'

이를 제외한 다른 문자들은 유니코드 값으로 치환 또는 컴파일러에 의해 따로 해석됩니다.


전처리기 실행

  • #include 에 지정된 파일의 내용을 복사합니다.
  • #define 에 정의된 매크로를 사용해서 코드를 치환합니다.
  • #if, #ifndef 와 같은 구문들을 실행해서 코드를 치환합니다.
  • #pragma와 같은 컴파일러 명령문들을 해석합니다.
  • 전처리 단계가 끝난 이후의 컴파일러 소스 예시
// 실행 전
#inlcude <iostream>
int main()
{

}

--------------------------------------------
// 실행 후
namespace std
{
	...
}

namespace std
{
	...
}

namespace std
{
	...
}

.... 생략 

전처리 단계가 끝난 이후 컴파일러가 보는 소스는 다음과 같이 변하게 됩니다.
#include 로 복사된 헤더 파일은 다시 1번부터 4번까지의 과정을 거칩니다.
이와 같은 문제를 해결 하기 위해서 미리 컴파일된 헤더(Pre Compiled Header) 라는 개념이 도입되었습니다.


인접 문자열 합치기

// 변경 전
std::cout << "abc"
             "def";
// 변경 후
std::cout << "abcdef";


3. 선언과 정의

유일정의 규칙 (One Definition Rule)

모든 변수, 함수 ,클래스 등등의 정의는 유일 해야하고, inline이 아닌 모든 함수의 변수들의 정의는 전체 프로그램에서 유일해야 한다. 이것이 유일 정의규칙입니다.

  1. 동일한 이름의 엔티티는 한 번만 정의되어야 합니다.
  1. 선언과 정의는 유일해야 합니다.
  1. 같은 구조체나 클래스가 서로 다른 헤더파일에서 정의되더라도, 내부 구현이 동일하면 문제가 없습니다.


  • 변수의 유일 정의
// file1.cpp
int x = 5; // 정의

// file2.cpp
extern int x; // 선언

여기서 int x = 5;는 변수 x를 정의하는 것이며, extern int x;는 변수 x를 선언하는 것입니다.

이때 extern 키워드는 "이 변수는 다른 파일에서 정의되었음"을 나타냅니다. 이는 ODR을 지키고 있습니다.


  • 함수의 유일 정의
// file.cpp
void myFunction() {
    // 함수의 정의 내용
}

// file2.cpp
void myFunction(); // 함수의 선언

여기서 void myFunction() {...}는 함수 myFunction의 정의이며, void myFunction();는 함수 myFunction의 선언입니다.

함수를 사용하는 코드에서는 선언만 알고 있어도 됩니다.

ODR은 여러 파일에 함수를 정의하더라도, 컴파일러가 정의를 합칠 수 있도록 합니다.


  • 클래스의 유일 정의
// file1.cpp
class MyClass {
    // 클래스의 정의 내용
};

// file2.cpp
class MyClass; // 클래스의 선언

여기서 class MyClass {...};는 클래스 MyClass의 정의이며, class MyClass;는 클래스 MyClass의 선언입니다.

클래스를 사용하는 코드에서는 선언만 알고 있어도 됩니다.

ODR은 여러 파일에 클래스를 정의하더라도, 컴파일러가 정의를 합칠 수 있도록 합니다.


선언

컴파일러에게 변수, 함수, 클래스 또는 다른 프로그램 요소가 존재함을 알려주는 것입니다.

int x;
void func();


정의


int x;
int x = 1;
void func()
{
	x++;
}

정의는 변수, 함수, 클래스 등을 실제로 생성하고 메모리를 할당합니다.

정의선언정의 \supset 선언

정의는 선언에 포함됩니다.

모든 정의는 선언이다. (참)

모든 선언은 정의이다. (거짓)


정의와 선언


extern const int a;      // a 를 선언하였지만 정의하지 않음
extern const int b = 1;  // b 를 정의함

하지만 extern 지정자가 들어간 선언의 경우 명시적으로 초기화 되지 않는다면 선언입니다.

struct S {
  int n;                // S::n 정의
  static int i;         // S::i 정의
  inline static int x;  // S::x 를 정의
};                      // S 를 정의

클래스 정의 내부에 inline이 아닌 static 멤버의 경우에도 정의입니다.


?. 문제 풀이

문제 1.

전처리 과정에 대해서 설명해주세요.


문제 2.

C++에서 유일 정의 규칙에 대해서 설명하고 유일 정의 규칙이 성립하기 위한 조건을 자세하게 설명해주세요.


문제 3.

다음 예시에서 ? 에 해당하는 부분에 선언과 정의인지 말해주세요.


// 1.
extern int intVal;		// ?

// 2. 
struct S {				// ?
  int n;                // ?
  static int i;         // ?
  inline static int x;  // ?
}; 

// 3.

class MyClass { 	// ?
    static int x; 	// ?
};
profile
그냥 해라

0개의 댓글