일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- tipssoft
- 함수
- Visual Studio
- c
- 백준
- 리뷰
- 알고리즘
- c++
- 김성엽
- 이지스퍼블리싱
- Javascript
- 프로그래밍
- CS
- 문법
- 배열
- VS ERROR
- Direct2D
- Tips강좌
- Tips프로그래밍강좌
- doit코틀린프로그래밍
- 연산자
- 지식나눔강좌
- Desktop
- 티스토리
- Kotlin
- Win32
- Windows
- Programming
- 포인터
- c#
- Yesterday
- Today
- Total
F.R.I.D.A.Y.
매크로 함수를 사용할 때 주의할 점 본문
조금 복잡한 계산들. 즉, 복잡한 수식들을 반복해서 작성하기는 여간 귀찮은 것이 아닙니다. 그래서 우리는 전처리 명령어(define)를 이용해서 매크로 함수로 그 수식을 대신하곤 합니다. 이번 포스트에서는 이 매크로 함수를 작성할 때 무엇을 주의해야 하는지 알아봅니다.
매크로 함수
일단 아래 코드를 예시로 들겠습니다. 간단히 두 수를 더하는 함수를 만들었다고 합시다.
#include <stdio.h>
int add(int a, int b){
return a +b;
}
int main(void){
int a,b;
scanf("%d %d", &a, &b);
printf("%d + %d = %d\n", a, b, add(a,b));
return 0;
}
우리 블로거는 add 함수를 이용하는 것은 프로그램 속도에 영향을 주기 때문에 다른 방법을 이용하기로 합니다. 바로 매크로 함수입니다.
#include <stdio.h>
#define add(a,b) a + b
int main(void){
int a,b;
scanf("%d %d", &a, &b);
printf("%d + %d = %d\n", a, b, add(a,b));
return 0;
}
이제 이 프로그램을 실행해보면 정상적으로 두 입력값의 합산 결과가 나오게 됩니다.
그런데 이 블로거가 조금 더 계산하기로 했습니다. 입력받은 두 값의 연산 결과에 10을 곱하기로 말이죠.
#include <stdio.h>
#define add(a,b) a + b
int main(void){
int a,b;
scanf("%d %d", &a, &b);
printf("%d + %d = %d\n", a, b, add(a,b) * 10);
return 0;
}
이 코드는 함수에서는 문제가 없습니다. 그러나 함수가 아닌 매크로 함수, 특히나 위 코드와 같이 작성된 매크로 함수의 경우에는 문제가 발생합니다. 이것은 전처리 지시자의 특성에 의한 것으로 특성에 대한 내용은 다음 링크를 참고하세요. 핵심은 아래 문장입니다.
전처리 지시자는 치환의 성격을 띠다 보니, 위 코드는 결국 아래 코드로 변경되어 컴파일이 진행됩니다.
#include <stdio.h>
int main(void){
int a,b;
scanf("%d %d", &a, &b);
printf("%d + %d = %d\n", a, b, a + b * 10);
return 0;
}
사칙연산(프로그래밍)의 우선순위는 [곱셈 = 나눗셈 > 뺄셈 = 덧셈]입니다. 우리 의도는 a와 b의 값을 더한 후, 그 결과에 10을 곱하는 것인데 위 코드는 명백히 b와 10을 곱한 값을 a에 더하는 식이 되어버립니다. 전처리 지시자가 치환의 특성을 띤다는 점을 꼭 기억해야 하는 이유입니다.
그렇다면 이 문제를 어떻게 해결해야 할까요? 사용하지 않기에는 매크로 함수는 너무 편리합니다.
괄호 이용
이 문제는 결국 연산자 우선순위로 발생하는 문제였습니다. 따라서 우리는 매크로 함수 내부를 연산자 우선순위로 조정해주면 됩니다. 괄호를 이용합니다.
#include <stdio.h>
#define add(a,b) (a + b)
int main(void){
int a,b;
scanf("%d %d", &a, &b);
printf("%d + %d = %d\n", a, b, add(a,b) * 10);
return 0;
}
add 매크로 함수에 괄호 하나 더 넣었을 뿐인데 이제 의도한 대로 값이 출력됩니다. 어린 개발자가 자주 하기 쉬운 실수입니다. 위 사례뿐만 아니라 아래와 같은 문제들도 있습니다.
#include <stdio.h>
#define mul(a,b) (a * b)
int main(void){
int a,b;
scanf("%d %d", &a, &b);
printf("%d * %d = %d\n", a, b, mul(a,b));
return 0;
}
add 매크로 함수를 곱하는 mul 함수로 변경했습니다. 앞서 괄호를 이용하라고 했던 조언을 받아 괄호도 작성했습니다. 그러나 이 코드도 문제가 발생할 수 있는 코드입니다.
printf("%d * %d = %d\n", a, b, mul(a+1,b+1));
만일 위와 같은 코드를 작성하면 어떻게 될까요? 예시로 a에는 4, b에는 10을 넣어보겠습니다.
15가 출력됩니다. 왜 이런 문제가 발생할까요? 앞서 언급드린 것과 마찬가지로 전처리 지시자의 특성인 치환 때문입니다. 위 코드를 치환하면 아래와 같은 코드로 변경됩니다.
printf("%d * %d = %d\n", a, b, (a+1 * b+1));
풀어 보면 결국 a와 b, 그리고 1을 더하는 것으로 바뀌어 버립니다. 이러한 경험을 바탕으로 우리는 매크로 함수로 들어오는 인자에도 괄호를 작성해주어야 한다는 결론에 도달하게 됩니다.
#define add(x, y) ((x) + (y))
#define mul(x, y) ((x) * (y))
등과 같은 코드처럼 말이죠.
'DEV > C C++' 카테고리의 다른 글
void 포인터(메모리) (0) | 2019.12.08 |
---|---|
calloc의 인자는 왜 두 개가 필요할까? (1) | 2019.12.05 |
함수 포인터를 배워야 하는 이유2 : callback 함수 (3) | 2019.11.17 |
주가 스팬 계산하기 (1) | 2019.11.14 |
여러 괄호를 사용하는 VPS 찾기 (0) | 2019.11.13 |