Qaupot Blog
Software Engineering, Trip

206. 전처리기 (Preprocessor)

🕐 Fri, 07 Feb 2014 09:00:00 GMT 🕓 Fri, 20 Aug 2021 10:57:00 GMT

전처리기(Preprocessor)

전처리기는 컴파일 과정 중 어휘분석 단계 이후에 동작합니다.
프로그램에 직접적으로 속하는 코드라기 보다는, 컴파일러에게 내리는 지시사항과 같습니다.

C/C++에서 전처리 코드는 #으로 시작합니다.

#include

가장 익숙한 #include 는 다음에 지정하는 파일을 이 소스코드를 컴파일하기 전에 읽어들이라는 지시입니다.

괄호의 형태로는 환경변수에 지정된 경로, 따옴표의 형태는 현재 코드가 위치한 곳으로 부터의 상대주소로 파일을 지시합니다.

<>로 엮을 경우 환경 변수 경로로부터 이 파일을 찾게 되며,
""로 엮을경우 현재 이 소스코드가 위치한 경로부터 헤더를 찾게 됩니다.

#include <stdio.h>
#include "main.h"

#define / #undef

#define은 특정한 단어 혹은 수식을 치환하는 정의식입니다.
#define A B의 형태로 사용되며, A를 B로 치환할 것을 지시합니다.

#define MAXIMUM 300 이라고 하면
이 코드에 등장하는 MAXIMUM 이라는 이름은 모두 300이라는 숫자값으로 치환됩니다.

조금 더 복잡한 흔히 매크로 함수라 하는 함수형태의 치환 방법도 존재합니다.

#define Plus(A,B) A+B 

int result = Plus(1,2) 라고 사용했을때,
이는 int result = 1+2로 치환되어 result 에는 3이라는 값이 대입됩니다.

함수의 형태처럼 인수를 만들면 그 인수가 해당하는 부분에 치환되는 방식이라고 할 수 있습니다.

  • 단순한 치환식이기 때문에 매크로 함수의 인수는 자료형의 구분을 하지 않습니다.
  • 함수를 실제 사용한 지점에서 치환된 결과물이 문법적 오류가 있다면 컴파일 과정에서 에러로 표기될 것입니다.

#undef는 #define으로 정의한 부분을 해제할 때에 사용합니다.

#define MAXIMUM 20
#define BYTE char
#define Plus(A,B) A + B
#undef MAXIMUM

이를 잘 이용하면 반복되는 코드를 #define과 #undef을 이용한 헤더파일 처리를 통하여 줄이는 것도 가능합니다.

#ifdef

#ifdef와 #endif, 그리고 #else #elif는 함께 사용되는 조건부 컴파일 지시자입니다.

#ifdef \_\_WIN32
void Init() {}
#endif

조건부 컴파일 지시자가 나오기 전까지 __WIN32가 정의 되어 있으면, void Init(){}부분을 컴파일 하며, 그렇지 않다면 무시합니다.

  • #define __WIN32의 형태로 정의 되어 있어야 합니다.
#ifdef \_\_WIN32
void Init() { OS = \_WIN32;}
#elif \_\_LINUX
void Init() { OS = \_LINUX;}
#else
void Init() { OS = \_FAIL;})
#endif

#elif와 #else는 #ifdef 다음에 추가로 조건을 걸거나 혹은 나머지에 대해 전부 처리할 사항을 기입합니다.

조건부 컴파일문은 위의 예제와 같이 공통의 선언부에 구현부를 따로 만들때 주로 이용됩니다.
예를 들어, print 라는 함수를 만들면 그 원형은 전부 같겠지만, 플랫폼에 따라 지원되는 함수들이 다를 수 있으므로 그 구현방식이 달라질 수 있습니다.

선언부는 공통적으로 유지하되, 구현부를 조건부 컴파일로 나누어 놓으면, 프로그램의 큰 틀은 유지하면서 여러 플랫폼에서 동작하는 소스코드를 작성할 수 있습니다.

#error

#error는 컴파일러에게 의도적인 에러를 발생시키도록 합니다.

주로 #ifdef ~ #endif와 함께 사용되며, 특정한 함수나 기능을 지원하지 않는 경우, 컴파일을 하지 못하도록 하며, 그 이유를 설명할때 사용하게 됩니다.

#ifdef \_\_WIN32
void Init() { OS = \_WIN32;}
#elif \_\_LINUX
void Init() { OS = \_LINUX;}
#else
#error UnknownPlatform
#endif

위의 코드는 WIN32나 LINUX 가 아니면 UnknownPlatform 이라는 컴파일 에러를 발생시킵니다.

#line

#line은 기본 정의인 __FILE__과 __LINE__을 재 정의하도록 합니다. 자주 사용되지는 않습니다.

  • __FILE__은 소스코드의 이름 매크로
  • __LINE__은 소스코드 내 현재 라인수를 표기하는 매크로

#line A B의 형태로 사용하며, A는 __LINE__의 값을, B는 __FILE__의 값을 변경합니다.

  • #line 2 "MainFunc"와 같은 방식입니다.

#pragma

#pragma는 일종의 확장 지시자입니다.

각 회사의 컴파일러별로 C/C++표준에 속하지 않는 독자적인 지원을 하는 경우가 있으며, #pragma로 컴파일러에 지시를 내립니다.

#pragma once
#pragma warning

#pragma once 는 헤더파일에 사용하며, 이 헤더파일을 한번만 부르도록 제어하는 지시자입니다.
이는 MS VisualStudio 에서는 잘 동작하지만, GCC 에서는 경고를 출력합니다.

  • GCC 도 지원은 하지만 사용하지 않을 것을 권고 하고 있습니다.
이 블로그는 개인 블로그입니다. 게시글은 오류를 포함하고 있을 수 있지만, 저자는 오류를 해결하기 위해 노력하고 있습니다.
게시글에 별도의 고지가 없는 경우, 크리에이티브 커먼즈 저작자표시-비영리-변경금지 4.0 라이선스를 따릅니다.

This blog is personal blog. published posts may contain some errors, but author doing efforts to clear errors.
If post have not notice of license, it under creative commons Attribution-NonCommercial-NoDerivatives 4.0.