2012년 8월 9일 목요일

전처리기 지시어.

전처리 지시어는 컴파일 직전에 처리된다.

#include
ex> #include <stdio.h>
이 지시어는 헤더 파일을 지시어가 들어가 있는 위치에 헤더파일을 포함시키는 것이다. < >괄호를 사용하면 표준 헤더 파일 디렉토리에서 지정한 파일을 찾는다. 같은 폴더일 경우에는 " "괄호를 사용한다. 물론 <>, ""의경우 어떤 것을 사용해도 상관은 없다 해당 폴더를 검색해서 해당 파일이 없다면 다른 폴더도 검색하기 때문이다.

#define
ex> #define NUM 1
(치환전) int Arr[NUM]; -> (치환후) int Arr[1];
이 지시어는 거의 치환의 의미로 사용됩니다. 위의 NUM을 컴파일하기전에 전처리기는 1로 대체한다. NUM이 어디에 있든 찾아내서 1로 바꾼다.

ex> #define TEXT "전처리 지시어"
(치환전) printf("%s", TEXT); -> (치환후) printf("%s", "전처리 지시어");
또한 정수형과 같이 문자열로도 치환이 가능하다.

ex> #define MAX
#ifdef MAX
  //MAX가 define되어 있다면 해당 코드가 컴파일 된다.
#else
  //MAX가 define되어 있지 않다면 해당 코드가 컴파일 된다.
#endif
또한 MAX로 정의는 하지만 대치시키지는 않도록 할수도 있다. 이것은 #ifdef ~ #elif ~ #else ~ #endif 문과 같이 사용되면 상당히 유용하게 사용된다. 이런것을 조건부 컴파일이라 한다.

#undef
ex>
#undef MAX
//이 아래 부터서는 MAX는 정의 되어 있지 않게 된다.
#ifdef MAX
  //MAX가 undef 되어 코드를 컴파일하지 않는다.
#else
  //MAX가 undef 되어 코드를 컴파일 한다.
#endif
이 지시어는 define으로 정의된 것을 해제하는 것으로 해당 코드 아래 부터서는 MAX의 정의가 되어 있지 않은 것으로 간주 한다.

ex>
#define SIZE 100
i = SIZE;
#undef SIZE
#define SIZE 200
j = SIZE;
또한 Define으로 정의한 것을 다시 정의하면 컴파일 에러를 일의킨다. 이때 사용하는 것이 undef이다. 위와 같이 사용하면 컴파일 에러는 나지 않는다.

#if, #else, #endif
ex>
#if 0
  //if 가 0 이기 때문에 이 코드는 컴파일 되지 않는다.
#else
  //if 가 0 이기 때문에 이 코드는 컴파일 된다.
#endif
이 지시어는 일반 적인 if문과 동일 방식으로 동작한다.

#if 0
  //대용량 코드
#endif
또한 대용량코드를 주석 처리를 하지 않고 한번에 컴파일에서 삭제가 가능하다는 것이다.

#ifdef, #elif
ex>
#ifdef MAX1
  //MAX1 이 정의 되어 있다면 이곳의 코드를 컴파일 한다.
#elif MAX2
  //MAX1 이 정의 되어 있지않고 MAX2가 정의 되어 있다면 이곳의 코드를 컴파일 한다.
#else
  //MAX1 과 MAX2 가 정의 되어 있지 않다면 이곳의 코드를 컴파일 한다.
#endif
이 지시어는 MAX1 과 MAX2가 정의(Define)되었는지 체크하고 그에 해당하는 코드를 컴파일하게 된다.

#ifndef
ex>
#ifndef FILENAME_H
#define FILENAME_H
  //코드
#endif
이 지시어는 ifdef와 반대로 해당 수식어(FILENAME_H)가 정의 되어 있지 않다면 참으로  #endif 까지의 코드를 컴파일 하게 된다.
또한 이것은 헤더 파일이 중복되어 선언 되지 않도록 할때 자주 사용 되는 방식이다.

defined()
ex>
#if defined(DEBUG1) || defined(DEBUG2) || defined(DEBUG3)
  #define GEN_DEBUG(x) {printf x;}
#else
  #define GEN_DEBUG(x)
#endif
이 지시어는 해당디파인이 되어있다면 1을 아니면 0을 반환한다. 일반 if문과 같이 사용하여 DEBUG1, DEBUG2, DEBUG3중 하나만 Define되어 있다면 참으로 인식하여 컴파일을 하게 된다. 이것은 디버그를 사용할때 자주 쓰이는 방식이다.

#error
ex>
#if !defined(__cplusplus)
#error C++ compiler required.
#endif
이 지시어는  전처리기가 해당 코드를 실행하게 되면 에러 메시지를 출력시키고 컴파일 작업을 하지 않도록 만든다.

#line
ex>
x = 1;                       //3번 라인
#line 100 "main.c"     //4번 라인
y = 1;                      //100번 라인
이 지시어는 사용자를 위한 문장이기 보다는 컴파일러 자체를 위한 프리프로세서문이다. 실제 컴파일 에러가나면 line을 거치면서 5번 라인이 아니라 100라인에서 에러가 난것으로 나타난다.

기타 전처리기 사용방법
매크로 함수(Macro function)
매크로 함수도 전처리기로 사용할 수 있다. 다만 디버깅이 힘들어 많이 사용되지 않는다.

ex> 
#define CUBE(x) ((x)*(x)*(x))
(치환전) y = CUBE(x);  -> (치환후) y = (x) * (x) * (x);

매크로 함수를 사용한다면 ()를 남발하는 습관을 키워야 한다.
ex>
#define CUBE(x) (x*x*x)
(치환전) y = CUBE(3+4);  ->  (치환후) y = (3+4 * 3+4 * 3+4);
위와 같은 경우 우리가 생각한 값은 나오지 않는다.
 C++ 사용자는 매크로 함수보다는 template이나 inline 함수를 사용해야 한다.

문자열 조작
ex>
#define SAY(x) printf(#x)

(치환전) SAY(Hello, world!);  ->  (치환후) printf(“Hello, world!”);

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

문자열 결합
ex>
#define Print(x) Print ## x
(치환전) Print(One)  ->  (치환후) PrintOne
(치환전) Print(Two)  ->  (치환후) PrintTwo
## 는 두 개의 문자열을 결합해 준다. 위와 같이 사용하면 PrintOne 이라는 문자열로 대치되고 Print(Two) 는 PrintTwo 라는 문자열로 대치된다.

assert()
 ex>
#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
대부분의 컴파일러는 ASSERT() 매크로를 가지고 있다.

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

또한 여러 줄이 필요할 때는 \ 가 사용되었다는 것에 유의하자.

ex> /* VC++6.0의 asert() */
#define _ASSERT(expr) \
        do { if (!(expr) && \
                (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, NULL))) \  //Debug 정보를 출력
             _CrtDbgBreak(); } while (0)  //자동으로 Debug Break를 잡아 준다. 이것 만으로도 유용하게 사용이 가능하다.

내장 매크로
ex>
printf(“ is NULL on line %d in file %s”, __LINE__, __FILE__);
컴파일 시에 컴파일러가 미리 정의하고 있는 매크로들 이다.

매크로명
 타입
 설명

__DATE__
 문자열
 컴파일하는 날짜

__TIME__
 문자열
 컴파일하는 시간

__LINE__
 정수
 컴파일하고 있는 줄 번호

__FILE__
 문자열
 현재 컴파일 하고 있는 파일의 이름

__TIMESTAMP__
 문자열
 소스 파일의 최종 변경 날짜와 시간


 ex>
printf("%d\n", __LINE__);  //컴파일시의 해당라인 번호로 치환된다. - 1234
printf("%s\n", __FILE__);  //컴파일시의 해당파일Path로 치환된다. - c:\main.c
printf("%s\n", __DATE__);  //컴파일시의 날짜로 치환된다. - Jan 1 2009 / 월.일.년
printf("%s\n", __TIME__);  //컴파일시의 시간으로 치환된다. - 15:31:17 / 24시간:분:초
printf("%s\n", __TIMESTAMP__);  //컴파일시의 날짜와 시간으로 치환된다. - Mon Jan 1 15:31:17 2009 / 요일.월.일.24시간:분:초.년

출처 : http://legendfinger.com/483

댓글 없음: