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
MUL은 a와 b를 곱하고, ADD는 a와 b를 더하도록 정의되어 있습니다.
// 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
MUL과 ADD를 정의할 때 a와 b, 결과를 모두 괄호로 묶어주었습니다.
// 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이 되어 덧셈이 먼저 계산됩니다.