반응형

cpp preprocessor (전처리기)


전처리기는 소스코드를 컴파일 전단계 (translation phase)에서 처리된다. (런타임이 아니다.) 전처리가 된 후 컴파일러로 전달된다.


+지시어

#으로 시작한다.

키워드로는 define, undef, include, if, ifdef, ifndef, else, elif, endif, line, error, pragma 가 있다.

null 지시어로 #만 쓰는 것도 가능하다. (아무일도 안 함.)


+기능

전처리기는 소스 파일의 번역을 한다.

소스의 일부를 조건에 따라 컴파일할 수 있다. (#if, #ifdef, #ifndef, #else, #elif, #endif)

텍스트를 변경하는 매크로 기능을 한다. (텍스트를 붙이거나 식별자를 스트링으로 사용하는 등) (#define, #undef,  오퍼레이터로써 # , ## )

다른 파일들을 포함시킬 수 있다. (#include)

에러를 발생시킬 수 있다. (#error)

파일명과 라인 번호 정보를 알 수 있다. ( #line )

지정된 방식으로 작업을 한다. (#pragma)


+조건적 포함

#if [expression]

#ifdef [identifier]

#ifndef [identifier]

#elif [expression]

#else

#endif

조건에 따라 코드 블록이 수행된다.


#if, #elif 뒤에 나오는 expression은 상수적 표현을 의미한다. unary 연산자를 포함할 수 있고,  defined identifier 나  defined (identifier) 를 사용할 수 있다. 

expression의 값이 non-zero이면 해당 블록이 처리되고, 0이면 스킵된다.


#ifdef, #ifndef는 다음과 같다. (identifer가 매크로명으로 정의되었는지 검사한다.)

#if defined identifier

#if !defined identifier


#define ABCD 2

#include <iostream>

int main()

{

#ifdef ABCD

std::cout << "1: yes\n" ;

#else

std::cout << "1:no\n" ;

#endif


#ifndef ABCD

std::cout << "2:no1\n" ;

#elif ABCD==2

std::cout << "2.yes\n" ;

#else

std::cout << "2.no2\n" ;

#endif


#if !defined(DCCA) && (ABCD < 2*4-3)

std::cout << "3. yes\n" ;

#endif

}

모두 yes가 출력됨.



+텍스트 변경 매크로

#define identifier    replacement-list

#define identifier(parameters)    replacement-list

#define identifier(parameters, ...)    replacement-list    (C++11)

#define identifier(...)    replacement-list (C++11)

#undef identifier


#define은 지정한 식별자를 replacement-list로 변경해 준다.

객체같은 매크로 ; identifier를 replacement-list로 교체한다.

함수같은 매크로 ; 위와 같지만 추가적으로 파라미터를 사용한다.

variable arguments의 경우 __VA_ARGS__ identifier를 사용한다. 

__VA_OPT__(content)는 __VA_ARGS__가 비어 있지 않을 경우 확장된다.

#define F(...)  f(0 __VA_OPT__(,) __VA_ARGS__)

F(1,2,3) --> f(0, 1,2,3)

F()    --> f(0)


#define G(X, ...)    f(0, X __VA_OPT__(,) __VA_ARGS__ )

G(a,b,c) --> f(0, a,b,c)

G(a,) --> f(0, a)

G(a) --> f(0, a)


#define SDEF(sname, ...)    S sname __VA_OPT__(= {__VA_ARGS__} )

SDEF(foo);    --> S foo;

SDEF(x, 1,2,3);    -->  S x = {1,2,3};



오퍼레이터 #, ##

함수같은 매크로에서 replacement-list 내부에서 식별자 앞에 # 오퍼레이터를 붙이면 결과를 ""로 묶게 된다. 내부에 "가 있으면 \도 자동으로 추가된다.

 

#define showlist(...)    puts(#__VA_ARGS__)

showlist() ;     -->  puts("") ;

showlist(1,"x", int);     --> puts("1, \"x\", int") ;


repplacement-list 내부에 연속된 두 개의 식별자 사이에 ## 오펴레이터가 추가되면 파라미터들을 두 식별자로 바꾸게 된다. 이 작업은 스트링을 붙여서 인식하게 된다.

#define Func(x) Func ##x

Func(1)    --> Func1 

Func(2)    --> Func2



#include <iostream>


#define FUNC(name, val) int FUNC_##name() {  return val ; }

FUNC(aaa, 10)

FUNC(bbb, 20)

FUNC(ccc, 30)

int main() {

    std::cout << FUNC_aaa()  << std::endl ;

    std::cout << FUNC_bbb()  << std::endl ;

    std::cout << FUNC_ccc()  << std::endl ;

return 0 ;

}

10, 20, 30이 출력된다.

FUNC(aaa, 10)   -->   int FUNC_aaa() { return 10 ; } 

위와 같이 풀린다.


+ Predefined macro

__FILE__    ; 현재 소스 파일명으로 확장 (string)

__LINE__    ; 현재 라인 번호 (int)

__DATE__    ; 컴파일 날짜(translation date)  "Mmm dd yyyy"

__TIME__    ; 컴파일 시간 "hh:mm:ss"


  • 소스 파일 포함 ; include

#include <filename>

#include "filename"

해당 파일을 그 위치에 포함시킨다.

C, C++ 라이브러리는 표준 include디렉터리에서 불러들인다. (include 디렉터리는 컴파일 옵션으로 설정할 수 있다.) 

""로 지정하면 소스파일의 디렉터리에서 검색한다. 못찾으면 표준 include 디렉터리에서 찾는다.

nested된 include에 의해 반복될 경우를 막기위해 다음과 같이 한 번한 include되게 한다.

#ifndef _FOO_H_

#define _FOO_H_

// to do..

#endif

pragma를 지원하는 컴파일러에서 아래와 같이 사용하면 위 효과를 동일하게 할 수 있다.

#pragma once


  • 에러 지시

#error error_message

위 지시자를 만나면 에러 메시지를 출력한다.  컴파일 시점에서 발생한다.

#if !WINDOWS_XP && !WINDOWS_7

#error Please check your OS

#endif


  • 파일명과 줄번호 정보

#line lineno

#line lineno "filename"

다음 줄 라인 번호를 lineno로 변경한다. 매크로 __LINE__ 값이 바뀐다.

뒤에 파일명을 주면 __FILE__ 매크로인 파일명이 바뀐다.


#line 777 "test.cc"

assert(2+2==5) ;

위 소스를 컴파일 할 경우, test.cc:777 에서 assertion 에러가 발생한다.



'Develop > C&CPP' 카테고리의 다른 글

if or 비교시 어떤 식의 성공으로 진입했는지 구분  (0) 2018.07.13
Numerics library  (0) 2018.06.21
deque  (0) 2018.06.13
stack / queue  (0) 2018.06.12
cstring  (0) 2018.06.11

+ Recent posts