75 매크로 사용하기

C 언어에서는 컴파일러에 특정 작업을 지시하는 전처리기(preprocessor)를 제공합니다. 보통 전처리기는 반복되는 값이나 작업을 미리 정의할 때 사용하며 컴파일 옵션 설정이나 조건부 컴파일도 가능합니다.

이번에는 전처리기에서 #define으로 매크로를 정의하는 방법을 알아보겠습니다.

75.1 매크로 정의하기

배열이나 동적 메모리를 할당한 포인터는 반복문과 함께 사용하는 경우가 많습니다. 보통 배열, 메모리 크기만큼 반복하면서 값을 출력하거나 저장하죠.

간단하게 배열을 선언한 뒤 반복문으로 문자를 하나씩 저장하고 출력해 보겠습니다.

array.c

#include <stdio.h>

int main()
{
    char s1[10];    // 문자 10개 크기의 배열 선언

    for (int i = 0; i < 10; i++)    // 배열 크기만큼 반복
    {
        s1[i] = 97 + i;
    }

    for (int i = 0; i < 10; i++)    // 배열 크기만큼 반복
    {
        printf("%c ", s1[i]);
    }

    return 0;
}

실행 결과

a b c d e f g h i j

이 코드의 문제점은 10이 3번 반복된다는 점입니다. 만약 배열의 크기를 바꾸면 반복문에 있는 10도 전부 바꿔야 합니다. 여기서는 10이 3개뿐이라 바꾸는데 큰 문제가 없지만, 사용하는 부분이 많아지면 숫자를 바꾸기도 점점 힘들어지고 실수할 가능성도 높아집니다.

특히, 10은 배열 s1의 크기를 뜻하지만, 코드에 내용이 더 추가돼서 배열의 크기와는 별개로 10을 사용할 수도 있습니다. 즉, 의미가 서로 다른 10이 섞여서 사용되면 각각의 의미가 헷갈리기 쉽습니다.

이런 문제를 해결할 때는 매크로를 정의하면 됩니다. #define 지시자는 값을 다른 이름으로 정의하며 이름을 짓는 방법은 변수와 같습니다. 보통 매크로는 대문자를 사용합니다.

  • #define 매크로이름 값

다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

define_macro.c

#include <stdio.h>

#define ARRAY_SIZE 10    // 10을 ARRAY_SIZE로 정의

int main()
{
    char s1[ARRAY_SIZE];    // 10 대신 ARRAY_SIZE 매크로 사용

    for (int i = 0; i < ARRAY_SIZE; i++)    // 10 대신 ARRAY_SIZE 매크로 사용
    {
        s1[i] = 97 + i;
    }

    for (int i = 0; i < ARRAY_SIZE; i++)    // 10 대신 ARRAY_SIZE 매크로 사용
    {
        printf("%c ", s1[i]);
    }

    return 0;
}

실행 결과

a b c d e f g h i j

먼저 #define을 사용하여 값 10을 ARRAY_SIZE로 정의했습니다.

#define ARRAY_SIZE 10    // 10을 ARRAY_SIZE로 정의

이제 10을 써야 할 자리에 앞에서 정의한 ARRAY_SIZE 매크로를 사용했습니다. 배열을 선언할 때도 ARRAY_SIZE를 사용하고 반복문에서도 ARRAY_SIZE를 사용하니 코드가 좀 더 명확해졌죠?

char s1[ARRAY_SIZE];    // 10 대신 ARRAY_SIZE 매크로 사용

for (int i = 0; i < ARRAY_SIZE; i++)    // 10 대신 ARRAY_SIZE 매크로 사용
{
    s1[i] = 97 + i;
}

for (int i = 0; i < ARRAY_SIZE; i++)    // 10 대신 ARRAY_SIZE 매크로 사용
{
    printf("%c ", s1[i]);
}

#define은 컴파일 직전에 처리되므로 전처리기 과정을 거치면 ARRAY_SIZE는 10으로 바뀌게 됩니다(바뀐 코드는 전처리기 과정 때 임시로 생성될 뿐 원본 코드에 영향을 주지 않으니 걱정하지 않아도 됩니다).

그림 75‑1 #define ARRAY_SIZE 10 적용

이처럼 연관되는 값이 계속 사용될 때는 값을 일일이 입력하기 보다는 매크로를 정의하여 사용하는 것이 좋습니다. 만약 배열 s1 크기를 변경하고 싶다면 #define 부분의 10을 수정하면 ARRAY_SIZE 매크로가 사용된 부분에 일괄 적용됩니다. 즉, 코드가 길어지고 복잡해졌을 때 코드 입력 실수를 줄일 수 있습니다.

참고 | 매크로를 매크로로 정의하기

#define으로 정의한 매크로는 다른 이름으로 다시 정의할 수 있습니다.

#define ARRAY_SIZE 10                     // 10을 ARRAY_SIZE로 정의
#define DEFAULT_ARRAY_SIZE ARRAY_SIZE     // ARRAY_SIZE를 DEFAULT_ARRAY_SIZE로 정의

이렇게 정의하면 결과적으로 DEFAULT_ARRAY_SIZE는 10입니다.

#define으로 정의한 매크로를 해제하고 싶을 때는 #undef를 사용합니다.

  • #undef 매크로이름

다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

undefine_macro.c

#include <stdio.h>

#define COUNT 10    // 10을 COUNT로 정의

int main()
{
    printf("%d\n", COUNT);    // 10

#undef COUNT        // 앞에서 정의한 COUNT 해제
#define COUNT 20    // 20을 COUNT로 정의

    printf("%d\n", COUNT);    // 20: #undef로 COUNT를 해제한 뒤 20을 COUNT로 정의했으므로 20이 출력됨

    return 0;
}

실행 결과

10
20

#define으로 정의한 매크로를 해제(삭제)하고 싶다면 #undef에 매크로 이름을 지정해주면 됩니다. 만약 #undef로 해제된 매크로를 계속 사용하면 컴파일 에러가 발생합니다.

여기서는 #undef을 사용하여 COUNT를 해제한 뒤 다시 #define을 사용하여 20을 COUNT로 정의했습니다.