제 28강) 전처리기(Pre-Processor) |
오늘은 전처리기(Pre-Processor)에 관한 것을 배웁니다.
전처리기 |
전처리기는 컴파일이 시작되기 "전"에 작동되는 것으로, 지시자를 통하여 처리기를 작동시킵니다.
(영어로는 PreCompiler, PreProcessor로 불립니다.)
전처리기 명령어(지시자)는 쉽게 육안으로 구분이 가능합니다.
#include <stdio.h>
#define PI 3.141592
#ifdef __SET_ON__
.....
#endif
#pragma once
이렇게 어떤 단어의 앞에 "#"이 붙으면 전처리기 명령어(지시자)가 됩니다.
#include |
아주 많이 써왔던 "#include" 입니다.
#include 파일
예)
#include <iostream>
#include <stdio.h>
#include "custom.h"
#include 다음에는 파일의 이름이 오는데 해당파일을 현재파일에 포함시키는 기능을 합니다.
#include는 크게 2가지로 사용을 하는데요.
#include <stdio.h> // 시스템 지정폴더(기본 C헤더 폴더)
#include "custom.h" // 현재 프로젝트의 폴더
이렇게 사용합니다.
헤더파일에 관한 설명은 다음강의에서 진행합니다.
#define 기본 |
우리가 상수에 대해서 배울때 봤던 #define입니다.
흔히 "매크로"라고 불립니다.
#define 매크로_이름 기능
예)
#define MAX 100
#define PI 3.141592
#define PRINT_A printf("A");
매크로는 이렇게 자료형(형식)에 상관없이 사용이 가능합니다.
심지어 6번처럼 함수를 사용할 수 있습니다.
(매크로보다 먼저 선언되었다는 전제하에)
#include <stdio.h>
#define ONE 1
#define TWO 2
#define MSG "오늘도 어제와 같은 하루"
#define PRINT_X printf("x: %d\n", x);
int main()
{
int x = ONE; // 컴파일시 int x = 1; 로 대치
PRINT_X; // 컴파일시 printf("x: %d\n", x); 로 대치
printf("%s\n", MSG); // 컴파일시 printf("%s\n", "오늘도 어제와 같은 하루"); 로 대치
printf("TWO: %d\n", TWO); // 컴파일시 printf("TWO: %d\n", 2); 로 대치
return 0;
}
매크로의 기본을 쉽게 접할 수 있는 예제입니다.
#define 전달 인자 사용 |
이 매크로를 진짜 함수처럼 전달인자를 주어 사용할 수 있습니다.
#define 매크로_이름(전달인자) 전달인자를_사용한_기능
예)
#define CIRCLE_AREA(X) (X)*(X)*3.14
#define PRINT_NUM(A) printf("%d\n", A);
이런 식으로 사용이 가능하다는 점입니다.
#include <stdio.h>
#define CIRCLE_AREA(X) (X)*(X)*3.14
#define PRINT_INT_NUM(A) printf("%d\n", A);
int main()
{
double r = 5.2;
printf("r의 원넓이: %f\n", CIRCLE_AREA(r));
PRINT_INT_NUM(15);
return 0;
}
아주 간단한 #define 전달인자 예제입니다.
이렇게 전달 인자를 사용할 때 주의해야 할 사항이 한 가지 있습니다.
(거의 모든 C언어 책에서 다루는 내용이지요)
다음 예제를 살펴봅시다.
#include <stdio.h>
#define MUL(X) X * X
int main()
{
printf("3 x 3 = %d\n", MUL(3));
printf("11 x 11 = %d\n", MUL(11));
printf("(2 + 4) x (2 + 4) = %d\n", MUL(2 + 4));
printf("2 + 4 x 2 + 4 = %d\n", (2 + 4 * 2 + 4));
printf("(9 - 3) x (9 - 3) = %d\n", MUL(9 - 3));
printf("9 - 3 x 9 - 3 = %d\n", (9 - 3 * 9 - 3));
return 0;
}
그리고 실행해봅시다.
뭔가 결과가 이상하지 않나요?
8번줄의 결과와 9번줄의 결과가 같아버리고, 10번줄의 결과와 11번줄의 결과가 같아버립니다.
#include <stdio.h>
#define MUL(X) X * X
int main()
{
printf("(2 + 4) x (2 + 4) = %d\n", MUL(2 + 4));
// MUL(2 + 4) = 2 + 4 * 2 + 4
printf("(9 - 3) x (9 - 3) = %d\n", MUL(9 - 3));
// MUL(9 - 3) = 9 - 3 * 9 - 3
return 0;
}
이렇게 해석을 해버립니다.
그럼 식에다가 괄호를 한 번 씌워봅시다.
#include <stdio.h>
#define MUL(X) (X) * (X)
int main()
{
printf("3 x 3 = %d\n", MUL(3));
printf("11 x 11 = %d\n", MUL(11));
printf("(2 + 4) x (2 + 4) = %d\n", MUL(2 + 4));
printf("2 + 4 x 2 + 4 = %d\n", (2 + 4 * 2 + 4));
printf("(9 - 3) x (9 - 3) = %d\n", MUL(9 - 3));
printf("9 - 3 x 9 - 3 = %d\n", (9 - 3 * 9 - 3));
return 0;
}
이전의 예제에서 MUL에 괄호만 붙였습니다.
그러나 결과는 원하는 결과가 나왔습니다.
괄호를 넣음으로써
#include <stdio.h>
#define MUL(X) (X) * (X)
int main()
{
printf("(2 + 4) x (2 + 4) = %d\n", MUL(2 + 4));
// MUL(2 + 4) = (2 + 4) * (2 + 4)
printf("(9 - 3) x (9 - 3) = %d\n", MUL(9 - 3));
// MUL(9 - 3) = (9 - 3) * (9 - 3)
return 0;
}
이렇게 식이 바뀝니다.
꼭 매크로로 수를 다뤄야 하는 경우에는 귀찮더라도 괄호로 싸줘야한다는 것!!
기억하세요.
#undef |
#undef 없애려는_매크로_이름
위에서 배운 #define으로 선언한 매크로를 무효화 시킵니다.
이렇게 #undef를 사용하면 이후에는 해당하는 매크로를 사용할 수 없습니다.
그럼 왜 undef를 사용할까요?
바로 매크로를 재정의 하기 위해서 주로 사용합니다.
(매크로는 undef를 이용하여 없앤 후에 다시 define을 이용해서 재정의 합니다.)
#ifdef, #else, #endif |
#ifdef 매크로_명
...
#else
...
#endif
위의 3지시자는 조건부 컴파일을 할 때 사용합니다.
설명보다는 예제를 통하여 알아봅시다.
#include <stdio.h>
#define KOR
int main()
{
#ifdef KOR // 만약 KOR이 #define 되어 있다면
printf("한국용 프로그램\n");
#else // KOR이 #define 되어있지
printf("해외용 프로그램\n");
#endif
printf("프로그램 종료\n");
return 0;
}
if ~ else와 비슷한데 define에 반응을 하는 지시자라고 보시면 됩니다.
만약 위의 예제에서 #define KOR이 없다면 "해외용 프로그램"이 나오겠죠?
#ifndef, #else, #endif |
#ifndef 매크로_명
...
#else
...
#endif
ifndef는 ifdef의 반대로 행동합니다.
#include <stdio.h>
#define KOR
int main()
{
#ifndef KOR // KOR이 #define 되어있지 않다면
printf("해외용 프로그램\n");
#else // KOR이 #define
printf("한국용 프로그램\n");
#endif
printf("프로그램 종료\n");
return 0;
}
if not define이기 때문에 ifdef와 반대로 작동한다는 것!!
#if와 #elif |
#if 매크로_명_조건
...
#elif 매크로_명_다른조건1
...
#elif 매크로_명_다른조건2
...
#else
...
#endif
#if와 #elif는 if ~ else if라고 보면 됩니다.
#include <stdio.h>
#define KO 1
#define EU 2
#define CN 3
#define EN 4
#define LANGUAGE EU
int main()
{
#if LANGUAGE == KO // KOR이 #define 되어있지 않다면
printf("한국용 프로그램\n");
#elif LANGUAGE == EU
printf("유럽용 프로그램\n");
#elif LANGUAGE == CN
printf("중국용 프로그램\n");
#else
printf("영어권 프로그램\n");
#endif
printf("프로그램 종료\n");
return 0;
}
조건에 사용하는 변수만 매크로로 바뀔뿐 모습은 if~else if~else와 비슷하다고 보시면 됩니다.
(전처리기가 관여하는 부분이기 때문에 내부적으로는 다릅니다.)
다음 시간에는 |
다음 시간에는 "파일의 분할"에 대해서 알아봅니다.
여기서는 헤더파일에 대해서도 알아봅니다.
'Study > C언어' 카테고리의 다른 글
처음하시는 분들을 위한 C언어 기초강의 시즌2 - 30 [전역변수와 정적변수(static)] (0) | 2018.10.28 |
---|---|
처음하시는 분들을 위한 C언어 기초강의 시즌2 - 29 [소스파일의 분할(헤더파일)] (0) | 2018.10.28 |
처음하시는 분들을 위한 C언어 기초강의 시즌2 - 23 [메모리 구조와 메모리 할당, 배열 동적할당(malloc, realloc, calloc, free)] (0) | 2018.10.28 |
처음하시는 분들을 위한 C언어 기초강의 시즌2 - 24 [구조체와 형식 정의 지정자(struct, typedef)] (0) | 2018.10.28 |
처음하시는 분들을 위한 C언어 기초강의 시즌2 - 25 [공용체와 열거형(union, enum)] (0) | 2018.10.28 |