전처리기

C++에서 #이 붙은 요소는 전처리기(preprocessor)라고 불리웁니다. 컴파일을 하기전에 미리 처리해야하는 내용입니다. 우리가 지금까지 코드를 작성하며 사용했던 전처리기는 #include 뿐이지만 #define과 #if, #ifdef, #ifndef, #else, #elif, #endif등 다양한 전처리기가 존재합니다. 각각의 요소에 대해서 알아보도록 하겠습니다.


#include

#include <iostream>

int main(void) {
    std::cout << "Hello, World!" << endl;
    return 0;
}

#include는 외부에 있는 파일을 포함시켜 하나의 파일처럼 컴파일을 할 수 있습니다. 우리는 분명히 std::cout이라는 함수를 만든적이 없었지만 사용할 수 있습니다. 이는 우리가 포함시킨 iostream에 해당 함수가 들어있기 때문입니다. #include를 이용하여 이런 기본적인 헤더 파일을 불러올 수 있고 사용자가 만든 헤더파일과 소스코드를 묶어줄수도 있습니다.


#if

#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#endif

#ifdef linux
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#endif

#if, #ifdef, #ifndef, #else, #elif, #endif는 굉장히 다양한 방면으로 사용됩니다. 가령 헤더파일이 중복되어 불러와지지 않도록 할 수 있으며 운영체제를 구분하여 부분적으로 소스코드를 제거하거나 추가할 수 있습니다. 우리가 사용했던 if문과 동일한 기능을 수행하지만 위 나열된 전처리기의 경우는 대부분 시스템적인 측면에서 작동하는데 큰 의미가 있습니다.


#define

#define로 선언된 문자가 있다면 해당 문자는 컴파일시 지정한 문자로 변경됩니다. 한가지 예를 들어보겠습니다.

#include <iostream>
#define MY_NAME "BaeJino"
#define YEAR 2019
#define MONTH "Apr"
#define DAY 2

using namespace std;

int main(void){
    cout << "Hello, My name is " << MY_NAME << endl;
    cout << "Today is " << DAY << " " << MONTH << " " << YEAR << endl;
    return 0;
}
Hello, My name is BaeJino
Today is 2 Apr 2019

재미있게도 우리는 변수를 단 하나도 생성하지 않았지만 변수를 생성한 것 처럼 출력하고 있습니다. 이는 메모리를 할당받는 것이 아니라 바꿔치기 한다고 생각하시면 좋습니다. 한마디로 위 코드는 애초에 다음과 같이 만들어 진 것입니다.

#include <iostream>

using namespace std;

int main(void){
    cout << "Hello, My name is " << "BaeJino" << endl;
    cout << "Today is " << 4 << " " << "Apr" << " " << 2019 << endl;
    return 0;
}

#define을 이용하면 다음과 같이 재미난 한글 코딩을 구현할 수도 있습니다.

#define으로 선언된 것은 변형시키거나 다른 값을 넣을 수 없습니다. 마치 상수(const)처럼요. 그럼 이상하네요. #define이 있는데 왜 const를 사용하는 것일까요? 저는 프로그래밍 언어를 배울때 이 부분이 항상 궁금했습니다. #define과 const는 다음과 같은 차이가 있습니다.


Const와 Define의 차이

  • const는 메모리를 할당 받는다
#include <iostream>

#define TEST_VARIABLE_DEFINE 2+5
const int TEST_VARIABLE_CONST = 2+5;

using namespace std;

int main(void) {
    cout << TEST_VARIABLE_DEFINE * 6 << endl;
    cout << TEST_VARIABLE_CONST  * 6 << endl;
    return 0;
}

두 값의 결과는 어떨까요? 같을까요? 결론부터 말하면 다릅니다.

32 (2 + 5 * 6)
35 ((2 + 5) * 6)

define은 값이 바꿔치기 된 것이라고 말했습니다. const는 메모리를 할당받은 변수죠. 변수에 대입한 값이 이미 계산이 완료된 상태로 들어있는 상태라는 의미입니다. 그래서 메모리를 극도로 조절해야 하는 환경에서는 define을 선호한다고 합니다.


  • const는 변수다
#define YEAR 2019
#define MONTH "Apr"
#define DAY 2

const int kYear = 2019;
const char[5] kMonth = "Apr";
const int kDay = 2;

define은 단순히 치환되는 값이므로 변수형을 지정할 필요가 없습니다. const는 변수이므로 반드시 변수형을 지정해 주어야 합니다. 따라서 const를 사용했을때 프로그래머가 발생하는 오류를 더 쉽게 감지할 수 있습니다.


  • const는 한번 초기화할 수 있다
#include <iostream>

class People {
    const int age = 0;
public:
    People(int x) : age(x) {}
    int print_age() {
        return age;
    }
};

using namespace std;

int main(void){
    People me(100);
    cout << me.print_age() << endl;
    return 0;
}

const와 define의 차이점에서 가장 큰 부분이라 생각합니다. const는 변경할 수 없는 상수라고 했지만 클래스의 생성자를 호출하는 과정에서 발생하는 멤버 이니셜라이져에서 한번 초기화할 수 있습니다.