[C++] 전처리문


Study/C , C++ , MFC  2020. 3. 17. 12:18

안녕하세요. 명월입니다.


이 글은 C++에서 전처리문에 대한 글입니다.

전처리문이란 C++이 컴파일해서 실행되기 전에 처리되는 소스 메크로라고 생각하면 됩니다.

간단한 예를 들면 debug 상태에서 실행되어야 할 소스나 값이 있고 release 상태에서 실행되어야 할 소스나 값이 있는데 그걸 전처리문으로 처리할 수 있는 것입니다.

#include <stdio.h>
#include <iostream>
using namespace std;
// 실행 함수
int main()
{
// 전처리기 _DEBUG가 있을 경우 아래의 구문을 실행
#ifdef _DEBUG
  // 콘솔 출력
  cout << " DEBUG MODE " << endl;
// 전처리기 _DEBUG가 없을 경우 아래의 구문을 실행
#else
  // 콘솔 출력
  cout << " RELEASE MODE " << endl;
#endif
  return 0;
}

 


위 예제를 보면 Debug 모드에는 콘솔 출력을 DEBUG MODE로 하고 Release 모드에서는 RELEASE MODE가 표시되게 설정하였습니다.

이는 ifdef는 define된 변수가 _DEBUG가 있을 때와 없을 때를 구분으로 실행하는 것입니다. 이 define은 프로젝트의 속성으로 가면 설정하는 탭이 있습니다.


전처리문의 종류는 총 12가지 정도 있습니다.

전처리기 설명
조건부 포함 전처리문(Conditional inclusions)
#if 전처리 분기문 if에 해당됩니다. define에 정의 값을 비교합니다.
#elif 전처리 분기문 else if에 해당됩니다. define에 정의 값을 비교한다. elif 전처리문 단독으로 사용할 수 없습니다.
#else 전처리 분기문 else에 해당됩니다. else 전처리문 단독으로 사용할 수 없습니다.
#endif 전처리 분기문의 종료에 해당합니다.
#ifdef define 전처기문이 정의되어 있으면 해당된다.
#ifndef define 전처기문이 정의되어 않으면 해당된다.
매크로 정의 전처리문(macro definitions)
#define 전처리 매크로 및 상수 정의
#undef 정의된 전처리문을 무효화한다.
디버깅 라인 전처리문(Line control)
#line 이미 정의된 전처리문 __LINE__에 소스 정의 라인을 재정의하기 위한 전처리문
에러 탐지 전처리문(Error directive)
#error Runtime 중이 아닌 compile 단계에서 일부러 에러를 발생시킬 때 사용한다.
소스 포함 처리 전처리문(Source file inclusion)
#include 보통 해더 파일을 읽을 때 사용합니다. 최종 빌드 전의 이진 파일이 아닌 소스 형태의 파일을 읽을 때 사용합니다.
지시어 전처리문(Pragma directive)
#pragma pragma는 세가지 형태로 사용된다. 가장 많이 사용되는 #pragma once는 해더를 여러 곳에서 참조할 경우 한번만 읽는 기능, 즉, a.cpp 소스에서 common.h를 읽고 b.cpp 소스에서 common.h을 읽을 려고 할 때 a.cpp에서 먼저 읽었기 때문에 두번 읽지는 않는다.
#pragma comment(lib, 파일이름.lib) 등 해더 내에서 library 참조시에 사용된다. visual studio에 기본적으로 선언되어 있는 lib는 kernel32.lib, user32.lib, gdi32.lib, winspool.lib, comdlg32.lib, advapi32.lib, shell32.lib, ole32.lib, oleaut32.lib, uuid.lib, odbc32.lib, odbccp32.lib
#pragma warning(disable:4702)는 4702의 에러를 무시해 주는 전처리 문입니다.
사전 정의된 전처리문(Predefined macro names)
__LINE__ 컴파일 중인 소스 코드 파일의 현재 행을 나타내는 정수 값입니다.
__FILE__ 컴파일 중인 소스 파일의 추정 이름이 포함 된 문자열 리터럴입니다.
__DATE__ 컴파일 프로세스가 시작된 날짜를 포함하는 "Mmm dd yyyy"형식의 문자열 리터럴입니다.
__TIME__ 컴파일 프로세스가 시작된 시간을 포함하는 "hh : mm : ss"형식의 문자열 리터럴입니다.
__cplusplus 정수 값. 모든 C ++ 컴파일러에는이 상수가 일정한 값으로 정의되어 있습니다. (컴파일러의 버젼과 비슷한 설정)
__STDC_HOSTED__ 구현이 호스팅 된 구현 인 경우 (모든 표준 헤더 사용 가능) 그렇지 않으면 0입니다.
// 중복 읽기 금지 전처리문
#pragma once
// 소스 포함 전처리문
#include <stdio.h>
#include <iostream>
// 메크로 정의 전처리문
#define Squared(x) x*x
// 정의 전처리문
#define TEST
using namespace std;
// 시작 함수
int main()
{
// 라인 재설정
#line 1
#ifdef TEST
  // 2의 제곱은 4이면
  #if Squared(2) == 4
    // 콘솔 출력
    cout << " 2 Squared? " << 4 << endl;
  // 2의 제곱은 5이면
  #elif Squared(2) == 5
    // 콘솔 출력
    cout << " 2 Squared? " << 5 << endl;
  // 그 외
  #else
    // 콘솔 출력
    cout << " 2 Squared is unknown. " << 5 << endl;
  #endif
  // 콘솔 출력
  cout << "Line is " << __LINE__ << endl;
#else
  // 에러!
  #error ERROR!!
#endif
  return 0;
}

실행 결과입니다.

전처리문은 소스가 컴파일 되기 전의 소스 레벨에서 이루어지기 때문에 Visual studio를 보시면 이미 폰트의 색으로 어느 영역이 실행되는지 알 수가 있습니다. 그리고 전처리문은 Runtime레벨이 아닌 소스 레벨이기 때문에 사용하기에 따라서 성능을 향상시킬수도 저하시킬수도 있습니다.

물론 사양에 따른 이지만, 개인적인 생각은 전처리문과 template 기능을 잘 사용하면 성능을 놀라울 정도로 향상 시킬수 있고, 아예 새로운 언어 문법을 창조시킬 수도 있습니다.


여기까지 C++에서 전처리문에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.