본문 바로가기
Object-C

ANSI 표준에 따른 C의 전처리문의 종류

by 풍야 2010. 3. 11.


ANSI 표준에 따른 C의 전처리문의 종류

- 파일 처리를 위한 전처리문 : #include

- 형태 정의를 위한 전처리문 : #define, #undef

- 조건 처리를 위한 전처리문 : #if, #ifdef, #ifndef, #else, #elif, #endif

- 에러 처리를 위한 전처리문 : #error

- 디버깅을 위한 전처리문 : #line

- 컴파일 옵션 처리를 위한 전처리문 : #pragma

조건 처리를 위한 전처리문은 어떤 조건에 대한 검사를 하고 그 결과를 참(0 이 아닌 값) 또는 거짓(0)으로
돌려준다.

#if : ...이 참이라면
#ifdef : ...이 정의되어 있다면
#else : #if나 #ifdef에 대응된다.
#elif : 'else + if'의 의미
#endif : #if, #ifdef, #infdef이 끝났음을 알린다.


#if ~ #endif
#if 구문은 if랑 아주 비슷하다. 이것은 어떠한 구문을 컴파일 할지 안할지를 지정할 수 있다:
#define A 1
#if A
source code ...
#endif

위 source code 부분은 컴파일이 된다. if문에서와 같이 참, 거짓을 구분하여 컴파일이 된다. 위에서 A값은 1 즉 0보다 큰 수이기 때문에 참인 것이다. 직접 아래와 같이 하면 거짓이기 때문에 source code 부분은 컴파일이 되지 않는다:
#if 0
source code ...
#endif

#ifdef ~ #endif
컴파일 할 때
#define MYDEF                /* MYDEF는 값은 가지지 않았지만 어쨋든 정의는 되었다 */

#ifdef YOURDEF              /* 만약 YOURDEF가 정의되어 있다면... */
#define BASE 10             /* BASE == 10 */
#elif MYDEF                    /* 그외에 MYDEF가 정의되었다면... */
#define BASE 2               /* BASE == 2 */
#endif

BASE는 상수 2로 치환되어 전처리기가 컴파일러에게 넘겨준다.

#ifndef 헤더명_H__ ~ #endif
헤더 파일이 겹치는 것을 막기 위한 일종의 매크로이다. 예를 들어, 헤더 파일에 어떤 클래스의 인터페이스 선언을 넣었다고 하자. 이 클래스 인터페이스에서 다른 파일의 프로토타입이 필요해서 다른 A 파일을 include 하고 있는데 이 헤더 파일을 include 하는 파일에서 A라는 헤더 파일을 이미 include 하고 있다면 두번 define한 것이 된다. 그러면 SYNTEX 에러가 난다. 그래서 그런 것을 막는 방법의 하나로 #ifndef을 사용한다. 이전에 include되어 있으면 #endif 쪽으로 점프해 버려 결국 한번 선언되는 것이다:
#include  <stdio.h>    ------ (a)
#include  <stdio.h>    ------ (b)

이렇게 두번 썼다고 하자. 그런데 앞에 이미 include를 했는데 밑에 또 한다면 문제가 된다. 컴파일러가 검사해야할 코드량도 많아진다. 그래서 stdio.h에는
#ifndef STDIO_H__
#define STDIO_H__
가 선언되어 있다. 만약 STDIO_H가 선언되어 있지 않다면 선언한다는 뜻이다. 그 뒤 (b)에서는 이미 (a)쪽에서 STDIO_H__ 을 선언한 상태이기 때문에 전처리기 쪽에서 무시해버린다. 그러므로 컴파일러는 (a)만 검사한다.

#defined
define이 여러 개 되어 있는지를 검사할 때 쓴다. 이것은 여러 개를 동시에 검사 할 수 있다:
#if (defined A) || (defined B)

#ifdef와 #if defined의 차이
#ifdef은 정의가 되어 있는지를 테스트 하기 때문에, 한번에 여러 개를 사용할 수 없다:
#ifdef name

여러 개가 정의되어 있는지를 테스트 하기 위해서 #if defined를 사용할 수 있다:
#if defined(MACRO1) || defined(MACRO2)

#if는 ||로 중첩해서 사용할 수 있다. 형식이, #if expression이므로 C 표현이 올 수 있다:
#if (MACRO1) || (MACRO2)

#error
소스 라인에 직접 에러 메세지를 출력한다. 전처리기가 #error 문을 만나면 그 즉시 컴파일을 중단하고 다음과 같은 에러 메시지를 출력한다:
ERROR : XXXXX.c ########: Error directive: 내용
- XXXXX.c --> 현재 컴파일 중인 파일 명
- ####### --> 전처리기가 #error 문을 만난 시점에서의 행 번호(헤더 포함)

#ifdef __LARGE__
#error This program must be compiled in LARGE memory model!
#endif

이 내용은 만일 프로그램이 LARGE 모델이 아니라면 "#error" 뒤에 표시된 메세지를 출력하고 컴파일을 중지하게 된다.

#line
이 명령은 소스 코드의 행 번호를 지정하기 위한 것으로 주로 컴파일러에 의해 미리 정의된 __LINE__과 함께 사용된다.
__LINE__과 __FILE__을 각각 행 번호와 파일 명으로 변경한다:
#include <stdio.h>
#define DEBUG

void main(void)
{
        int count = 100;

        #line 100               /* 다음 줄번호를 100으로 설정한다 */
                                   /* <-- 이 줄의 번호가 100이다 */
        #ifdef DEBUG        /* <-- 이 줄의 번호가 101이다 */
        printf("line:%d, count = %d\n", __LINE__, count);
        #endif

        count = count * count - 56;
        #ifdef DEBUG
        printf("line:%d, count = %d\n", __LINE__, count);
        #endif
        count = count / 2 + 48;
        #ifdef DEBUG
        printf("line:%d, count = %d\n", __LINE__, count);
        #endif
}