[KNK] CH14 - The preprocessor

2 분 소요

CH14 - The preprocessor

preprocesser는 어떻게 작동하는가

#있는 문장이 오면 대체한다. #include로 헤더파일 앞에 있는 함수들울 앞에다가 그대로 복사하고 #define으로 매크로를 그대로 대체한다.

Preprocessing Directives

  • Macro definition: #define
  • File inclusion: #include
  • Conditional compilation: #if, #ifdef, #ifndef, #elif, #else, #endif

\기호로 줄이 넘어가도 사용 가능

매크로 정의

  • #define identifier(capitalized) replacement-list
  • #define identifier(parameter’s) replacement-list (이경우 전처리과정에서 대체가 안된다)

(주의) parameterized macro의 경우 매개변수마다 괄호를 붙이고 매크로 전체에 괄호를 붙인다.

#define MAX(x,y) ((x)>(y)?(x):(y))
#define IS_EVEN(n) ((n)%2==0)

매크로와 함수의 장점

  • 매크로가 좀더 빠름
  • 변수가 좀더 generic

매크로와 함수의 단점

  • 컴파일코드가 길어질 수 있음
  • augments are not type-checked
  • 포인터사용 못함
  • augment 계산이 여러번 될 수 있음
    MAX(i++,j)=( (i++) > (j) ? (i++) : (j) )
    

# operator

매개변수를 string literal로 만든다.

#define PRINT_INT(n) printf(#n "= %d\n",n)
PRINT_INT(i/j);
printf("i/j" "= %d\n",i/j);

parameterized macro가 #operator를 nest한 상황에서는 쓸 수 없다.

#define N 10
#define STR(x) #x
STR(N)="N"(not "10")

##operator

token을 붙인다.

#define MK_ID(n) i##n
int MK_ID(1), MK_ID(2);
int i1, i2;

parameterized macro가 nest한 상황에서는 쓸 수 없다.

#define CONCAT(a,b) a##b
CONCAT(a,CONCAT(b,c)) => aCONCAT(b,c)

매크로의 일반적 특징

다른 매크로를 쓸 수 있다. #define DOUBLE_PI (2*PI) #undef로 매크로 해제가 가능

comma(,) operator

함수, 함수;

Predefined Macros

__LINE__ //줄표시
__FILE__ //파일 이름표시
__DATE__ //"Mmm dd yyyy"
__TIME__ //"hh:mm:ss"
__STDC__ //표준(c89 or c99)을 따르면 1
__STDC__HOSTED__(c99) //c99표준을 반드시 따르면 1(hosted)/ 0(freestanding)
__STDC_VERSION__(c99) //yyyymmL(long integer of the date of amendment of the c)
__STDC_IEC_599__ //??
__STDC_IEC_599_COMPLEX__ //??
__STDC_ISO_10646__ //??

Empty Macro Arguments(c99)도 가능하다(w/o parameter)

Macros with a variable number of arguments(c99)

#define TEST(condition, ...) ((condition)?\
  printf("Passed test: %s\n", #condition): \
  printf(__VA_ARGS__))
// __VA_ARGS__는 나머지 ...에 있는 parameter들을 그대로 내보낸다
TEST(voltage<=max_voltage,"Voltage %d exceeds %d",voltage,max_voltage);
// if true -> Passed test: voltage <= max_voltage
// if false -> Voltage 125 exceeds 120

__func__ Identifier(c99) //not related with preprocessor!!
// string literal, unnecessary declaration

Conditional Compilation

#if, #endif, #elif, #else

#if constant_expression //시작 
// condition에 따라 존재여부 결정
// statement....
#elif constant_expression
// statement....
#else
// statement...
#endif//끝맺음

‘defined’ operator

#if defined(DEBUG)(또는 #if defined DEBUG) //DEBUG의 정의 여부를 따짐
statement
#endif

#ifdef와 #ifndef

// identifier가 정의 됐을 때
#ifdef identifier
#if defined(identifier)
//identifier가 정의되지 않았을 때
#ifndef identifier 
#if !defined(identifier)

#ifdef와 \if defined의 차이점: #ifdef or #ifndef와 달리 defined는 &&, || 연산자를 사용할 수 있다.

Uses of conditional Compilation

  • 여러 종류의 머신과 OS에서 작동하도록 함
  • 여러 종류의 컴파일러에서 컴파일 되도록 함
  • 컴파일 시점에 매크로를 정의하여 특정코드가 컴파일 되지 않도록 함

Miscellaneous Directives

#error

#error message(printed message vary from one compiler to another)

#line

  • #line은 LINE__과 __FILE(생략가능)매크로를 재정의
  • #line 1 “abc.c”: 다음행부터 LINE__은 1부터 시작, __FILE=”abc.c”
  • 프로그래머들이 사용 잘 안함

#pragma

  • #pragma tokens : 컴파일러 지시용, 컴파일러마다 문법이 다름
  • #pragma tokens=_Pragma (“tokens”) (c99)

댓글남기기