75.5 매크로와 연산자 우선순위 알아보기

매크로를 정의할 때는 연산자 우선순위를 주의해야 합니다. 먼저 두 수를 곱하는 매크로와 더하는 매크로를 정의해보겠습니다.

macro_operator_precedence_wrong.c

#include <stdio.h>

// a와 b를 곱함
#define MUL(a, b) a * b

// a와 b를 더함
#define ADD(a, b) a + b

int main()
{
    printf("%d\n", MUL(10, 20));          // 200: 10 * 20
    printf("%d\n", MUL(1 + 2, 3 + 4));    // 11: 1 + 6 + 4, 2 * 3이 먼저 계산됨

    printf("%d\n", ADD(1, 2));        // 3: 1 + 2
    printf("%d\n", ADD(1, 2) * 3);    // 7: 1 + 6, 2 * 3이 먼저 계산됨

    return 0;
}

실행 결과

200
11
3
7

MULab를 곱하고, ADDab를 더하도록 정의되어 있습니다.

// a와 b를 곱함
#define MUL(a, b) a * b

// a와 b를 더함
#define ADD(a, b) a + b

이제 매크로를 사용해보면 MUL(10, 20)은 200이 잘 나오지만 MUL(1 + 2, 3 + 4)은 3 * 7의 결과인 21이 나오지 않고 11이 나왔습니다. 마찬가지로 ADD(1, 2)는 결과가 잘 나오지만 ADD(1, 2) * 3은 9가 나와야 하는데 7이 나왔습니다.

printf("%d\n", MUL(10, 20));          // 200: 10 * 20
printf("%d\n", MUL(1 + 2, 3 + 4));    // 11: 1 + 6 + 4, 2 * 3이 먼저 계산됨

printf("%d\n", ADD(1, 2));        // 3: 1 + 2
printf("%d\n", ADD(1, 2) * 3);    // 7: 1 + 6, 2 * 3이 먼저 계산됨

왜냐하면 MUL이 전처리기를 거쳤을 때 다음과 같은 모양이 되므로 연산자 우선순위에 따라 2 * 3이 먼저 계산됩니다. 즉, 1 + 6 + 4라서 11이 나오게 됩니다.

/*
  a       b
  ↓       ↓    */
1 + 2 * 3 + 4
//    ↑ 먼저 계산됨

마찬가지로 ADD도 전처리기를 거치면 숫자와 연산자가 그냥 나열됩니다. 여기서도 연산자 우선순위에 따라 덧셈보다 곱셈이 먼저 계산되므로 2 * 3이 먼저 계산됩니다. 1 + 6이라서 7이 되죠.

/*
a   b
↓   ↓     */
1 + 2 * 3
//    ↑ 먼저 계산됨

이렇게 연산자 우선순위에 따라서 의도치 않게 계산 결과가 바뀌는 문제를 해결하려면 매크로의 인수와 결과를 모두 ( ) (괄호)로 묶어주면 됩니다.

macro_operator_precedence.c

#include <stdio.h>

// a와 b, 결과를 모두 괄호로 묶어줌
#define MUL(a, b) ((a) * (b))

// a와 b, 결과를 모두 괄호로 묶어줌
#define ADD(a, b) ((a) + (b))

int main()
{
    printf("%d\n", MUL(10, 20));          // 200: 10 * 20
    printf("%d\n", MUL(1 + 2, 3 + 4));    //  21:  3 * 7

    printf("%d\n", ADD(1, 2));        //   3:  1 + 2
    printf("%d\n", ADD(1, 2) * 3);    //   9:  3 * 3

    return 0;
}

실행 결과

200
21
3
9

MULADD를 정의할 때 ab, 결과를 모두 괄호로 묶어주었습니다.

// a와 b, 결과를 모두 괄호로 묶어줌
#define MUL(a, b) ((a) * (b))

// a와 b, 결과를 모두 괄호로 묶어줌
#define ADD(a, b) ((a) + (b))

이제 MUL(1 + 2, 3 + 4)은 전처리기를 거쳐도 ((1 + 2) * (3 + 4))와 같은 모양이 되므로 연산자 우선순위에 영향을 받지 않고 의도대로 계산이 됩니다. 마찬가지로 ADD(1, 2) * 3((1) + (2)) * 3이 되어 덧셈이 먼저 계산됩니다.