본문 바로가기

Languages/C

C언어 매크로(Macro)와 전처리기(Preprocessors) 총정리

 C언어를 이용해서 프로그램을 작성할 때 자동으로 떠오르는 그것이 있다. 자다 일어나서 정신이 없는 상태에서 컴퓨터 앞에 앉더라도 손가락이 기억하고 있는 그것.   

1
#include <stdio.h>
cs

 '#' 키워드는 컴파일러가 컴파일을 실행하기 전에 처리한다고 하여 전처리기(Preprocessor)라고도 하고 매크로라고도 한다. 그렇기에 우리가 전처리기를 이용해서 stdio.h라는 헤더파일을 불러오면 우리가 마음껏 scanf나 printf같은 함수들을 마음껏 사용할 수 있는 것이다. 

그런데 C언어에서는 우리에게 익숙한 #include 뿐만 아니라 다른 전처리기 연산들을 제공하고, 이를 이용하면 좀더 코드를 작성할 때 유용하게 사용할 수 있다.

1. 상수 정의

1
2
3
4
5
6
7
#include<stdio.h> 
#define MAX 10000 
int main() 
    printf("max is %d", MAX);
    return 0
cs

 MAX라는 int타입의 변수를 선언하여도 무방하지만, 이렇게 전처리기를 이용하여 컴파일러가 컴파일을 하기 전에 MAX자리를 100으로 치환하는 방법도 있다.

반대로 정의했던 것을 취소하는 키워드도 있다. 바로 undef이다. 아래처럼 MAX를 중간에 undef하면 애러가 발생하게된다.

 

1
2
3
4
5
6
7
8
9
10
#include <stdio.h> 
#define MAX 10000
int main() 
printf("%d",MAX); 
#undef MAX 
// 아래의 코드부터는 MAX가 정의되지 않기 때문에 애러가 난다.
printf("%d",MAX); 
return 0
cs

예상했던 Error 발생

 

2.  함수 정의

 전처리기를 이용하여 INCREMENT(x)라는 함수를 정의하였다. 정식 함수는 아니지만 함수처럼 작동한다. 매크로 함수의 장점은 문자열을 담기위한 char* 자료형과, int 자료형에 해당하는 함수를 각각 정의할 필요가 없다. char*의 값을 1늘렸기 때문에 h부터 출력됨을 알 수 있고 2003에서 2004로 1만큼 증가하여 출력됨을 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
#include <stdio.h> 
#define INCREMENT(x) ++
int main() 
    char *ptr = "Chaos and Order"
    int x = 2003
    printf("%s  ", INCREMENT(ptr)); 
    printf("%d", INCREMENT(x)); 
    return 0
cs

 

출력결과

그런데 산술 연산을 하는 함수를 전처리기로 정의할 때 반드시 주의할 점이 있다. 아래의 코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h> 
// !!괄호에 주의할 것!!
#define MULTIPLY1(a, b) a*
#define MULTIPLY2(a, b) (a)*(b) 
 
int main() 
    printf("%d\n", MULTIPLY1(2+33+5)); 
// Output: 16 = 2+3*3+5
    printf("%d\n", MULTIPLY2(2+33+5)); 
// Output: 40 = (2+3)*(3*5)
    return 0
 
cs

 우리가 원하는 값은 2+3과 3+5를 먼저 계산하고 곱한 값인 40인데 만약 우리가 전처리기를 MULTIPLY1과 같이 작성했다면 전혀 다른 값인 16이 출력되게 된다. 그래서 전처리기로 함수를 작성할 때는 피연산자 각각에 괄호를 씌우는 습관을 들여야 더욱 안전하고 원하는 결과값을 도출해내는 프로그램을 만들 수 있다.

출력결과

3. 문자열 매크로

 

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h> 
#define merge(a, b) a##b 
#define get(a) #a
int main() 
    // 두 숫자 합치기 #
    printf("%d\n", merge(1234)); 
    // 문자열로 변환하기 ##
    printf("%s\n", get(chaos and order)); 
 
cs

출력결과

4. 미리 정의된 매크로 상수

 언더슬래시 두개로 시작하여 언더슬래시 두개로 끝나는 여러가지 predefined된 상수들이 있다.

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h> 
 
int main() 
printf("현재 파일 :%s\n", __FILE__ ); 
printf("현재 날짜 :%s\n", __DATE__ ); 
printf("현재 시간 :%s\n", __TIME__ ); 
printf("파일 라인 수 :%d\n", __LINE__ ); 
return 0
 
cs

위의 4개 이외에도 여러가지 매크로 상수들이 존재하는데 자세한 것은 아래 링크로 들어가면 된다.

gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html

 

Standard Predefined Macros (The C Preprocessor)

This macro is defined when the C++ compiler is in use. You can use __cplusplus to test whether a header is compiled by a C compiler or a C++ compiler. This macro is similar to __STDC_VERSION__, in that it expands to a version number. Depending on the langu

gcc.gnu.org

5. 조건문 (ifdef, ifndef, if, endif)

 

일반적으로 파일의 크기가 커지면 헤더파일을 여러번 include하는 상황이 발생하고 그에따라 여러번 정의된 변수나 함수 때문에 자칫 문제가 발생할 수 있게된다. 따라서 한번만 include하면 좋은데 그 때 자주 사용하는 것이 ifdef와 ifndef이다. ifdef를 해석할 때는 "만약 ~가 정의되어있다면"으로 생각하면 되고 ifndef는 "만약 ~가 정의되어있지 않다면"으로 하면 된다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h> 
#define CHAOS
int main() 
#ifdef CHAOS
    printf("CHAOS는 정의됨\n");
#endif
#ifndef CHAOS
    printf("CHAOS는 정의되어 있지 않음\n");
#endif
#ifdef ORDER
    printf("ORDER는 정의됨\n");
#endif
#ifndef ORDER
    printf("ORDER는 정의되어 있지 않음\n");
#endif
cs

 

결과

 또한 전처리기에도 if나 else와 같은 역할을 하는 조건문이 있는데 그것은 바로 if와, endif 이다. 아래와 같이 평소에 분기문 처럼 사용하면 되고, 다른점이라면 분기문이 끝날 때 endif 키워드를 써줘야 한다.

 

1
2
3
4
5
6
7
8
9
10
#include <stdio.h> 
#define CHAOS 20
int main() 
#if CHAOS>=10
    printf("CHAOS는 10보다 같거나 큼\n");
#else
    printf("CHAOS는 10보다 작음\n");
#endif
cs

 

 

이상으로 C언어 매크로와 전처리기에 대한 포스팅을 마치겠습니다.