Programming/C, C++

[C/C++]전처리기 Pre-Processor

MB Kyle KWON 2013. 4. 18. 18:40

컴파일을 시도할 경우 컴파일이 실행되기 전에 전처리기 명령부터 처리된다.

전처리기는 # 로 시작하고 ; 를 붙이지 않으며 보이지 않게 소스 코드를 변경하며

컴파일러에게 지시를 내릴 수도 있다.

 

각각은 여기서는 명령어라는 용어를 사용했지만 정확하게는 directive(지시자라고 하는 것이 나을 지 모르겠다.

 

#include <header.h>

 

가장 흔히 볼 수 있는 전처리기이다해당 파일을 찾아서 컴파일러가 그 파일이 마치 현재 컴파일하는 소스 코드에 포함되어 있는 것같이 해준다. <> 는 표준 헤더 파일일 경우에 설정되어 있는 폴더에서 헤더 파일을 찾으며 “” 는 그 외 폴더에서 찾을 수 있는데 최우선으로 현재 프로젝트 폴더에서 찾게 된다.

 

#define

 

define 문은 여러 경우에 사용될 수 있는데 일반적으로 문자열 대치에 사용된다.

 

#define MAX 512

 

라고 하면 소스 코드에 있는 MAX 라는 문자를 모두 512 로 대치한다.

 

int Arr[MAX];

 

는 실제 컴파일러가 컴파일할 때는

 

int Arr[512];

 

로 대치될 것이다이것은

 

#define MAX 512

int Arr[MAX];

 

 

int Arr[512];

 

로 바뀐다고 생각하면 된다.

대치되는 문자 없이 그냥

 

#define MAX

 

로 사용되는 경우도 흔하다이것은 MAX 라는 문자열을 정의하지만 대치시키지는 않는다.

이렇게 사용하는 경우는 #ifdef ~ #elif ~ #else ~ #endif 문과 같이 사용되면 상당히 유용하게 사용된다.

 

#ifdef MAX

       cout << “Max is defined!” << endl;

#else

       cout << “Max is not defined!” << endl;

#endif

 

이렇게 사용하면 #define MAX  줄로 여러 버전의 실행 파일을 만들 수도 있다.

이런 것을 조건부 컴파일이라고 한다마지막 #endif  넣는 것도 잊지 말자.

 

#ifdef MAX

#elif defined(MIN)

#else

#endif

 

문이나

 

#if defined(MAX)

#elif defined(MIN)

#else

#endif

 

문등의 예제를  봐두기 바란다.

 

¨       관련된 주요 전처리기 명령어

 

¨       #ifdef 식별자

¨       #ifndef 식별자

¨       #undef 식별자

¨       #if defined(식별자)

¨       #if !defined(식별자)

¨       #elif

¨       #else

¨       #endif

 

#ifdef 등으로 식별자를 사용했으면

 

#undef 식별자

 

문으로 undef 하는 습관을 기르자. #undef 이후부터  식별자는 정의되지 않은 것으로 간주된다.

 

예제http://blog.naver.com/xtelite/50018568445

 

포함감시(Inclusion Guard)

 

여러 개의 헤더 파일(.h 또는 .hpp)과 구현 파일(.c 또는 .cpp) 들이 있을 경우 헤더 파일이 중복 포함되는 경우가 많다특히 C/C++에 입문한 지 얼마 안되는 사람들에게서 자주 나타나는 데 이런 경우 포함감시를 사용한다사실 포함감시 기능은 만드는 모든 헤더파일에 적용하도록 하자.

 

#ifndef FILENAME_H

#define FILENAME_H

 

// 여기에 헤더 파일의 모든 내용을 넣는다

 

#endif

 

이렇게 해 두면 두 번째 포함될 때 #ifndef 가 거짓이 되어 이 헤더 파일이 포함되지 않는다.

,

 

#include “filename.h”

#include “filename.h”

 

와 같이 하더라도 두 번째 헤더파일은 포함되지 않을 것이다. FILENAME_H 부분은 관례상 파일명을 이용해서 이렇게 명명한다. _FILENAME_H  __FILENAME_H__ 등 잘 사용되지 않는 문자열을 파일이름을 사용해서 만드는 것이다.

 

매크로 함수(Macro function)

 

매크로 함수도 전처리기로 흔히 사용된다다만 디버깅이 힘들다는 단점 때문에 점점 사용되지 않고 있기도 하다.

특히, C++의 경우 엄격한 형 검사를 하게 되는데 매크로 함수를 사용하게 되면 그 기능을 사용할 수 없으니 피해야 한다.

 

#define CUBE(x) ((x)*(x)*(x))

 

int x, y;

y = CUBE(x);

 

 

int x, y;

y = (x) * (x) * (x);

 

로 대치될 것이다매크로 함수를 사용한다면 ()를 남발하는 습관을 키워야 한다.

왜 그런지는

 

y = CUBE(3+4);

 

와 같은 경우에 직접 대치해 보면 알게 될 것이다.

 

C++ 사용자는 매크로 함수보다는 template이나 inline 함수를 사용해야 한다.

 

문자열 조작

 

#define SAY(x) printf(#x)

 

SAY(Hello, world!);

 

와 같이 식별자 앞에 # 를 붙이게 되면 자동으로 “x” 와 같이 “”로 둘러 싸 준다.

결과적으로

 

printf(“Hello, world!”);

 

로 대치될 것이다.

 

문자열 결합

 

## 는 두 개의 문자열을 결합해 준다.

 

#define Print(x) Print ## x

 

와 같이 된 경우

 

Print(One) 을 사용하면 PrintOne 이라는 문자열로 대치되고 Print(Two)  PrintTwo 라는 문자열로 대치된다잘 사용하면 아주 유용한 기능이 된다.

 

ASSERT()

 

대부분의 컴파일러는 ASSERT() 매크로를 가지고 있다여기서는 직접 하나 만들어 보자.

 

#ifndef DEBUG

#define ASSERT(x)

#else

#define ASSERT(x) \

       if ( ! (x) ) \

       { \

             printf(#x); \

             printf(“ is NULL on line %d in file %s”, __LINE__, __FILE__); \

       }

#endif

 

이 코드의 위에

 

#define DEBUG

 

한 줄 포함하면

 

#define ASSERT(x)

 

로 아무 일도 하지 않고 DEBUG가 정의되지 않으면 그 아래 함수가 정의된다.

디버그때만 코드가 생성되고 릴리즈시에는 코드가 생성되지 않게 할 수 있는 것이다.

 

여러 줄이 필요할 때는 \ 가 사용되었다는 것에 유의하자또한 내장 매크로인 __LINE__ 이나 __FILE__ 은 다음에 설명한다.

 

내장 매크로

 

컴파일 시에 컴파일러가 미리 정의하고 있는 매크로들이 있다.

각각 오른 쪽에 있는 내용으로 대치된다.

 

__DATE__ : 컴파일하는 날짜

__TIME__ : 컴파일하는 시간

__LINE__ : 현재 컴파일하고 있는 줄 번호

__FILE__ : 현재 컴파일하고 있는 파일의 이름

 

#error

 

컴파일러는 이 명령을 만나게 되면 해당 메지시를 출력하고 컴파일을 중지한다.

C++ 컴파일러에서만 동작하게 하는 다음 코드를 참조하자.

 

#if !defined(__cplusplus)

#error C++ compiler required.

#endif

 

__cplusplus  C++ 컴파일러일 경우에 정의되는 내장 매크로이다.

 

#pragma

 

#pragma 는 컴파일러마다 고유하게 사용할 수 있는 명령어이다따라서 그 문법은 컴파일러마다

다르고 그 종류도 많다.

 

예를 들어

 

#pragma once

 

같은 경우 위의 포함감시 기능을 컴파일러가 알아서 해 준다한 번 include 된 헤더 파일은 중복해서 포함되지 않도록 컴파일러가 처리해 준다.




출처 : http://blog.naver.com/xtelite?Redirect=Log&logNo=50023963913