01.11 - 전처리기 (preprocesser)
전처리기(preprocessor)는 프로그램을 컴파일할 때 컴파일 직전에 실행되는 별도의 프로그램이다. 전처리기가 실행되면 각 코드 파일에서 지시자(directives)를 찾는다. 지시자(directives)는 #으로 시작해서 줄 바꿈으로 끝나는 코드다.
전처리기는 컴파일러가 실행되기 직전에 단순히 텍스트를 조작하는 치환 역할을 하기도 하고, 디버깅에도 도움을 주며 헤더 파일의 중복 포함도 방지해주는 기능을 가진다.
Include
이전 포스트들에서 #include
지시자를 보았다. #include
를 하면 전처리기(prerocesser)는 포함(include)된 파일의 내용을 지시자의 위치에 복사한다. [전방 선언(forward declaration) 에 사용했었다.]
#include <filename>
<>
는 컴파일러와 함께 제공되는 헤더 파일을 include 할 때 사용한다. 위 헤더 파일은 C++ 런타임 라이브러리의 헤더 파일로써 운영체제의 특별한 위치에 존재한다.
#include "filename"
""
는 소스 파일이 있는 디렉터리에서 헤더 파일을 include 하도록 전처리기(preprocesser)에게 지시한다. 일반적으로 이와 같은 방법으로 자신이 작성한 헤더 파일을 include 한다.
Macro
#define
지시자를 사용해서 매크로(macro)를 만들 수 있다. 매크로는 입력을 출력으로 변환하는 방식을 정의하는 규칙이다.
매크로는 객체와 유사한 매크로(object-like macro)와 함수와 유사한 매크로(function-like macro)가 있다.
함수와 유사한 매크로(function-like macro)는 함수처럼 작동한다.
객체와 유사한 매크로(object-like macro)는 아래와 같이 두 가지 방법 중 하나로 정의한다.
#define identifier
#define identifier substitution_text
첫 번째 정의에서는 대체 텍스트가 없지만, 두 번째 정의에는 대체 텍스트가 있다. 지시자는 명령어가 아니므로 둘 다 세미콜론(;)으로 끝나지 않는다.
대체 텍스트가 있는 객체와 유사한 매크로 (Object-like macros with substitution text)
전처리기가 이 지시자를 발견하면 'identifier'은 앞으로 'substitution_text' 텍스트로 대체된다. 식별자(identifier)는 일반적으로 공백을 나타내는 밑줄을 사용하여 대문자로 모두 입력한다.
#define MY_FAVORITE_NUMBER 9
std::cout << "My favorite number is: " << MY_FAVORITE_NUMBER << std::endl;
전처리기(preprocessed)는 위 코드를 다음과 같이 치환한다.
std::cout << "My favorite number is: " << 9 << std::endl;
대체 텍스트가 없는 객체와 유사한 매크로 (Object-like macros without substitution text)
객체와 유사한 매크로는 대체 텍스트 없이도 정의할 수 있다.
#define USE_YEN
일반적으로 이 전처리 지시자는 조건부 컴파일(conditional compilation)을 하기위해 사용된다.
조건부 컴파일(Conditional compilation)
조건부 컴파일 전처리 지시자를 사용하면 컴파일할 조건이나 컴파일하지 않을 조건을 지정할 수 있다.
#ifdef
지시자를 사용하면 전처리기가 이전에 #
이 정의되었는지 아닌지를 확인한다. 정의되었다면 #ifdef
와 해당 #endif
사이의 코드가 컴파일된다. 그렇지 않으면 코드가 무시된다.
#define PRINT_JOE // PRINT_JOE 정의
#ifdef PRINT_JOE
std::cout << "Joe" << std::endl;
#endif
#ifdef PRINT_BOB
std::cout << "Bob" << std::endl;
#endif
PRINT_JOE
가 정의되었기 때문에 cout << "Joe" << endl;
는 컴파일된다. 그러나 PRINT_BOB
은 정의되지 않았기 때문에 cout << "Bob" << endl;
는 무시된다.
#ifndef
는 ifdef
의 반대다. 식별자(identifier)가 아직 정의되지 않았는지 확인한다.
#ifndef PRINT_BOB
std::cout << "Bob" << std::endl;
#endif
PRINT_BOB
는 아직 정의된 적이 없기 때문에 "Bob"은 출력된다.
번역: 이 포스트의 원문은 http://www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/ 입니다.