C 매크로 기본 - sonkoni/Koni-Wiki GitHub Wiki

매크로 사용하기

C언어 문법이 아니라 C컴파일러의 전처리기 명령어이다.
매크로는 C언어의 내부에서 각종 환경설정, 일반화 등 정말 엄청나게 많이 쓰인다.

  • 세미콜론 붙이지 않는다.
  • 주석은 보통 달지 않거나 별주석을 쓴다.
  • 보통 대문자_형태 로 쓴다.

매크로 정의와 해제

매크로의 주된 기능은 치환이다.

// 값을 매크로로 정의                    // 10을 COUNT로 정의
#define 매크로이름 값                   #define COUNT 10 

// 여러 줄을 매크로로 정의                // printf 세 줄을 PRINT_NUM3으로 정의
#define 매크로이름 코드1 \              #define PRINT_No3    printf("No\n"); \
                코드2 \                                   printf("NO\n"); \
                코드3                                     printf("nO\n");

// 값을 붙이는 매크로 정의(##)            // a와 b를 붙이는 CONCAT 매크로 정의
#define 매크로이름(a, b) a##b          #define CONCAT(a, b) a##b

// 문자열로 만드는 매크로(#)
#define PRINT(s)    printf(#s)      ==>> PRINT(hello);     
                                    ==>> printf("hello");  대치. , 변수를 따옴표로 싸준다.

// 정의한 매크로 해제               // COUNT 매크로 해제 
#undef 매크로이름                 #undef COUNT

매크로 함수

매크로를 함수처럼 쓸 수 있다. 간단한 경우에만 이렇게 하자. 요즘은 인라인 함수로 대체되는 분위기다.

// 함수 모양으로 매크로 정의         // 숫자를 출력하는 PRINT_NUM 매크로 정의
#define 매크로이름(x) 함수(x)       #define PRINT_NUM(x)    printf("%d\n", x)

#define 매크로이름(x) 코드조합      // do while (0)을 이용하여 매크로 안에서 변수 선언.
                               // if, else에서 컴파일 에러 방지
                                #define SWAP(a, b, type)    do { \
                                                                type temp; \
                                                                temp = a;  \
                                                                a = b;     \
                                                                b = temp;  \
                                                            } while (0)

매크로와 연산자 우선순위

매크로는 치환이다. 이로 인해 C언어 우선순위로 의도하지 않은 결과가 나올 수 있다. 괄호를 팍팍 써서 사용해야 한다

#define MUL(a, b)   a * b         ==>> MUL(1 + 2, 3 + 4)
                                  ==>> 1 + 2 * 3 + 4  대치. 결과는 11
#define MUL(a, b)   ((a) * (b))   ==>> MUL(1 + 2, 3 + 4)
                                  ==>> ((1 + 2) * (3 + 4))  대치. 결과는 21

괄호를 써주면 영향  받아
#define ADD(a, b)   a + b         ==>> ADD(1, 2) * 3
                                  ==>> 1 + 2 * 3   으로 대치. 결과는 7
#define ADD(a, b)   ((a) + (b))   ==>> ADD(1, 2) * 3
                                  ==>> ((1) + (2)) * 3   으로 대치. 결과는 9

조건부 컴파일

매크로 조건문이다. #ifdef, #ifndef, #if, defined, #elif, #else, enif 를 조합해서 사용한다.

// 매크로가 정의되어 있을 때 컴파일          // DEBUG 매크로가 정의되어 있을 때 컴파일
#ifdef 매크로                              #ifdef DEBUG
코드                                           printf("Debug\n");
#endif                                    #endif

// 매크로가 정의되어 있지 않을 때 컴파일      // DEBUG 매크로가 정의되어 있지 않을 때 컴파일
#ifndef 매크로                             #ifndef DEBUG
코드                                           printf("Hello, world!\n");
#endif                                    #endif

// 값 또는 식이 참일 때 컴파일              // DEBUG_LEVEL이 2 이상일 때 컴파일
#if 값 또는 식                             #if DEBUG_LEVEL >= 2
코드                                           printf("Debug Level 2\n");
#endif                                   #endif

                                      // 조건이 항상 거짓이므로 컴파일 하지 않음
                                          #if 0
                                              printf("0\n");
                                          #endif

                                      // 조건이 항상 참이므로 컴파일함
                                          #if 1
                                              printf("1\n");
                                          #endif

각종 논리연산자도 사용 가능하다.

// 매크로가 정의되어 있을 때 컴파일. 
// !, &&, ||로 논리 연산 가능             // DEBUG 또는 TEST가 정의되어 있을 때 컴파일
#if defined 매크로                       #if defined DEBUG || defined TEST
코드                                         printf("Debug\n");
#endif                                  #endif

                                      // DEBUG가 정의되어 있으면서 
                                      // VERSION_10이 정의되어 있지 않을 때 컴파일
                                         #if defined (DEBUG) && !defined (VERSION_10)
                                             printf("Debug\n");
                                         #endif

// if, elif, else로 조건부 컴파일         // DEBUG_LEVEL의 값에 따라 컴파일
#if 조건식                                #if DEBUG_LEVEL == 1
코드                                          printf("Debug Level 1\n");
#elif 조건식                              #elif DEBUG_LEVEL == 2
코드                                          printf("Debug Level 2\n");
#else                                    #else
코드                                          printf("Hello, world!\n");
#endif                                   #endif

// if, elif, else로 조건부 컴파일         // PS2, USB 정의 여부에 따라 컴파일
#ifdef 매크로                            #ifdef PS2
코드                                         printf("PS2\n");
#elif defined 매크로                     #elif defined USB
코드                                         printf("USB\n");
#else                                  #else
코드                                         printf("지원하지 않는 장치입니다.\n");
#endif                                 #endif

파일 포함하기

// 파일 포함하기
#include <시스템경로파일>  /* 기본 라이브러리나 컴파일 옵션에서 지정한 헤더파일 경로를 기준으로 포함 */
#include "임의경로파일"   /* 현재 소스파일을 기준으로 헤더파일 포함 */
    "msg.h"         현재소스와 같은 폴더에 있음
    "inc/msg.h"     현재폴더 하위 inc 디렉토리에 msg.h  있음
    "../msg.h"      현재폴더 상위 폴더에 msg.h  있음

소스파일 포함 시 중복 피하기

test.h / test.c 파일을 만든다고 할 때,
test.h 파일은 다음과 같이 구성해야 한다.

#ifndef 헤더이름                          #ifndef Test_h
#define 헤더이름                          #define Test_h
코드                                     #include <stdio.h>
                                        typedef struct _DATA {
                                            int a, b;
                                         } DATA;
#endif /* 헤더이름 */                      void GloHelloFunc (void);
                                        #endif /* Test_h */
⚠️ **GitHub.com Fallback** ⚠️