본문 바로가기

C++/Preprocessor Directives

C++ Preprocessor Directives

C++ 프로그래밍, 전처리 명령어 ( Preprocessor Directives )


전처리 명령어란?

C++ 언어로 코드를 작성하고 컴파일할 때 컴파일러에 앞서 실행되는 전처리 기능 프로그램 코드 중에서 #으로 시작되는 전처리 명령어를 찾아서 실행하게 된다. 전처리 명령은 일반적으로 코드의 일부분에 다른 코드를 포함하거나 조건에 따라서 일부의 코드를 추가하거나 매크로가 사용된 곳을 찾아서 지정된 코드로 대치하는 등의 기능을 한다. 전처리 명령에 따라서 변경된 소스코드는 비로소 컴파일 절차에 들어가게 된다.

전처리 명령어는 명령어가 입력된 한 행에만 영향을 미치고 행이 바뀌면 그 명령어의 효력은 종료된다. 그러므로 전처리 명령에는 마침표를 나타내는 세미콜른( ; )을 사용하지 않는다. 한 행 이상에 영향을 주려면 명령어가 입력된 행에 역슬래시(\)를 추가하면 다음 행에도 영향을 주게 된다


전처리 명령어를 이용한 매크로 선언 (Macro Definitions)

#define, #undef

#define 은 매크로를 선언하고 #undef 명령어는 선언된 매크로를 해제한다. 선언된 매크로가 사용된 코드 부분은 전처리 기능이 실행될 때 지정된 코드로 단순하게 대치된다. 그러므로 #define를 이용하여 표현식이나 연산자, 제어문, 코드 블럭 등 그 어떤 것도 매크로로 선언할 수 있다. 지정된 코드로 대치되었을 때 그 코드가 문법을 벗어나지 않으면 된다. 선언된 매크로를 해제하려면 #undef 를 사용한다

#include <iostream>
#include <locale>

using namespace std;

#define PI 3.141592
// 마치 함수처럼 보이는 함수 매크로(Function Macro)
#define get_area() 2*PI*3 // 위에서 선언된 매크로가 아래에 있는 다른 매크로에 사용될 수도 있다
// 함수 매크로에는 파라미터 전달도 가능하다
#define get_area2(r) 2*PI*r

int main() {
	setlocale(LC_ALL, "");
	wcout << L"C++ 전처리 명령어(Preprocessor Directives)" << endl;

	double area = get_area();
	wcout << L"반지름 3인 원의 면적=" << area << endl;

	area = get_area2(4);
	wcout << L"반지름 4인 원의 면적=" << area << endl;

	return 0;
}


함수 매크로(Function Macro)에서 사용되는 2개의 연산자(#, ##)

  • # : 함수 매크로의 아규먼트에 사용하여 문자열로 변환한다
  • ## : 좌우에 있는 코드를 결합한다
#include <iostream>
#include <locale>

using namespace std;

//함수 매크로에는 2개의 연산자(#, ##)를 사용할 수 있다
#define to_str(a) #a // #를 아규먼트 왼쪽에 붙이면 아규먼트는 문자열로 처리된다
//##은 함수 매크로 내에서 2개의 아규먼트를 결합한다. 문자열로 처리되지는 않는다.
#define combine(a,b) a ## b

int main() {
	setlocale(LC_ALL, "");
	wcout << L"C++ 전처리 명령어(Preprocessor Directives)" << endl;

	string str = to_str(5+5); // 해석되지 않고 그대로 문자열이 된다
	cout << str << endl; // 5+5

	combine(w,cout) << "Hello" << endl;
	return 0;
}


조건부 포함(Conditional Inclusions) 전처리 명령어

#ifdef, #ifndef, #if, #endif, #else, #elif

조건에 따라서 코드의 일부분을 컴파일에 포함하기도 하고 배제하기도 한다

#include <iostream>
#include <locale>

using namespace std;

#ifndef DEBUG
#define DEBUG
#endif

#ifdef DEBUG
#define d(m) wcout << "debug:" << m << endl
#endif

int main() {
    setlocale(LC_ALL, "");

    wcout << L"C++ Preprocessor Directives" << endl;
    d("msg");

    return 0;
}


#line : 컴파일 오류 발생시 오류가 발생한 행번호파일명이 출력되는데 이 때의 파일명과 행번호를 임의로 조작할 수 있다

디폴트 컴파일러 오류 발생시의 메시지 형태 (#line을 사용하지 않은 경우)

#include <iostream>
#include <locale>

using namespace std;

int main() {
    setlocale(LC_ALL, "");

    wcout << L"C++ Preprocessor Directives" << endl;

    int n = "5"; //..\src\CppApp.cpp:11:13: error: invalid conversion

    return 0;
}


#line 명령어를 이용한 컴파일러 오류 메시지 조작의 예 ( #line 행번호 "파일명" )

#include <iostream>
#include <locale>

using namespace std;

#line 7 "sample file" // 다음 행은 제 7행이 되어 컴파일 오류 메시지 행번호의 기준이 된다

int main() {
    setlocale(LC_ALL, "");

    wcout << L"C++ Preprocessor Directives" << endl;


    int n = "5";  //컴파일 오류가 있는 곳

    return 0;
}

위의 코드를 컴파일하면 다음과 같이 오류 메시지가 변경되어 출력되는 것을 확인할 수 있다

sample file: In function 'int main()':

sample file:14:13: error: invalid conversion


#error : 지정한 오류 메시지를 출력하고 컴파일을 중지한다

#include <iostream>
#include <locale>

using namespace std;

#ifndef MINGW
#error MinGW Compiler Required! // 여기서 지정한 메시지를 출력하고 컴파일을 중지한다
#endif

int main() {
    setlocale(LC_ALL, "");

    wcout << L"C++ Preprocessor Directives" << endl;

    return 0;
}


#include : 소스코드 파일을 현재 위치에 포함한다

  • #include "myheader"  : 현재 소스코드가 포함된 디렉토리에서 지정된 파일을 찾고 없으면 시스템에 설정된 헤더파일 경로에서 찾는다
  • #include <myheader> : 지정된 파일을 시스템에 설정된 헤더파일 경로에서 찾는다


#pragma : 컴파일러에 따라서 다양한 옵션을 설정할 때 사용한다. C, C++ 표준은 아니지만 널리 사용되고 있으며, VC++, GCC 등의 주요 컴파일러에서도 지원하고 있다. #pragma once 는 아래와 같은 환경에서 포함되는 헤더파일이 중복되지 않도록 설정할 때 흔히 사용된다

common.h

#pragma once   // 다른 파일에서 이 헤더파일이 중복되어 포함되는 것을 방지한다

struct Common{

}


header1.h

#include "common.h"


header2.h

#include "common.h"

#include "header1.h"


표준 매크로 : 다음과 같은 매크로는 표준으로 지원되므로 임의의 위치에서 사용할 수 있다

  • __LINE__  : 이 매크로가 있는 현재 코드의 행번호
  • __FILE__  :  현재 소스코드의 파일명
  • __DATE__  :  현재 날짜
  • __TIME__  : 현재시간(시분초)
  • __cplusplus  : C++ 버전
#include <iostream>
#include <locale>

using namespace std;

int main() {
    setlocale(LC_ALL, "");

    wcout << L"C++ Preprocessor Directives" << endl;
    wcout << L"행번호: " << __LINE__ << endl;
    wcout << L"파일명:" << __FILE__ << endl;
    wcout << L"날짜 :" << __DATE__ << endl;
    wcout << L"시간 :" << __TIME__ << endl;
    wcout << L"C++컴파일러 버전: " << __cplusplus << endl;

    return 0;
}

위의 코드 실행결과

C++ Preprocessor Directives

행번호: 10

파일명:..\src\CppApp.cpp

날짜 :Dec 29 2016

시간 :11:28:33

C++컴파일러 버전: 201402