본문 바로가기

Languages/C++

C매크로의 오동작의 예

DSL 15장에 매크로를 설명한 게 있어 나중에 예로 들 때 이용하도록 정리해 놓는다.


옳은 예)

예를 들어 두 숫자의 최댓값을 구해야 하는 경우가 많다고 해보자. 그래서  a > b ? a : b와 같은 형식을 C 언어를 사용해 중복작성해야 한다고 해보자.

#define max(x, y) x > y ? x : y


int a=5, b=7, c=0;

c = max(a,b);


나쁜 예1 - 잘못된 확장

하지만 매크로를 사용하면 미묘한 문제가 수없이 생겨서 곤경에 빠지기도 한다. 매크로에 파라미터를 사용하면 특히 그렇다. 숫자를 제곱하는 매크로를 생각해보자.

#define sqr(x) x * x


int a=5, b=1, c=0;

c = sqr(a + b);


6의 2승인 36이 나올 것이라고 기대했지만, c의 값은 11이 되어 버린다. 매크로가 확장되면서 표현식이 a + b * a + b 로 만들어지기 때문이다. *연산자가 +연산자보다 우선순위가 높으므로, 이 표현식은 (a + b) * (a + b)가 아니라, a + (b*a) + b로 계산된다.


해결책1

이 문제를 피하려면, Lisp 개발자가 사용하는 개수보다 더 많은 괄호를 사용해서 아래와 같이 작성해야 한다.

#define betterSqr(x) ((x) * (x))



나쁜 예2 - 중복평가

#define max(x, y) x > y ? x : y


int a=5, b=1, c=0;

c = max(++a, ++b);

증가연산자(++)가 있는 경우 함수일 경우에는 max(6, 2)을 예상하고 6일 것이라고 예상이 되지만, 매크로의 경우 7이 결과로 나와버린다. 이 코드는 중복 평가가 발행하는 예다. 매크로 몸체에서 이 인자를 한 번 이상 사용할 때 결국 인자는 여러 번 평가되게 된다. 이 예제에서는 a와 b는 모두 두 번 증가한다.



나쁜 예3 - 변수점유

#define cappedTotal(input, cap, result) \

{int i, total = 0; \

for(i=0; i<5; i++) \

  total = total + input[i];\

result = (total > cap) ? cap : total; }


int arr1[5] = {1, 2, 3, 4, 5};

int amount = 0;

cappedTotal(arr1, 10, amount);

int total = 0;

cappedTotal(arr1, 10, total);

하래 붉은 영역의 코드가 실행되면, total은 0이 된다. 괄호에 의해 스코프가 가려지기 때문이다.



'Languages > C++' 카테고리의 다른 글

별모양 찍기 : mvp 와 리팩토링  (0) 2021.04.12
소켓 프로그래밍 튜토리얼 at binarytides.com  (0) 2014.06.18
LLVM 컴파일러?  (0) 2013.10.09
V8 학습  (0) 2013.09.12
C++ web framework like spring for Java  (0) 2013.03.11