C 프로그래밍에서 매크로(Macro)와 함수(Function)는 비슷한 역할을 수행하는 것처럼 보이지만, 내부 동작 방식과 특성에서 중요한 차이가 있습니다. 이 글에서는 두 가지의 차이점을 예제 코드와 함께 자세히 살펴보겠습니다.
매크로와 함수의 기본적인 차이
가장 큰 차이는 처리 시점에 있습니다. 매크로는 전처리기(Preprocessor)에 의해 처리되므로, 컴파일이 시작되기 전에 모든 매크로가 단순 텍스트 치환 방식으로 확장됩니다. 반면 함수는 전처리 과정을 거치지 않고 직접 컴파일됩니다.
또한 매크로는 타입 검사(type checking)를 수행하지 않습니다. 따라서 다양한 타입의 입력값이 들어올 경우 문제가 발생할 수 있으며, 입력값이 적절히 관리되지 않으면 잘못된 결과를 생성할 위험이 있습니다.
문제를 보여주는 예제 코드
아래 프로그램은 같은 연산을 수행하는 함수와 매크로의 결과가 어떻게 달라지는지 보여줍니다.
#include <stdio.h>
#define SQUARE(x) x * x
int sqr(int x) {
return x*x;
}
main() {
printf("Use of sqr(). The value of sqr(3+2): %d\n", sqr(3+2));
printf("Use of SQUARE(). The value of SQUARE(3+2): %d", SQUARE(3+2));
}실행 결과
Use of sqr(). The value of sqr(3+2): 25 Use of SQUARE(). The value of SQUARE(3+2): 11
결과가 다른 이유
함수와 매크로 모두 제곱 값을 계산하도록 작성했지만, 출력 결과는 서로 다릅니다.
함수의 경우: 인자로 3 + 2를 전달하면 먼저 5로 계산된 후 함수에 전달되므로, 5 * 5 = 25라는 올바른 결과가 나옵니다.
매크로의 경우: 매크로는 단순 텍스트 치환이기 때문에 SQUARE(3+2)는 3 + 2 * 3 + 2로 확장됩니다. 연산자 우선순위에 따라 곱셈이 먼저 계산되어 3 + 6 + 2 = 11이라는 의도와 다른 결과가 나오게 됩니다.
매크로 사용이 권장되지 않는 이유
위와 같은 문제들로 인해 매크로 사용은 다음과 같은 이유로 권장되지 않습니다.
타입 검사가 없음 — 컴파일러가 인자의 자료형을 확인하지 못합니다.
디버깅이 어려움 — 단순 텍스트 치환 방식으로 동작하기 때문에 오류 추적이 쉽지 않습니다.
네임스페이스 부재 — 한 영역에서 정의된 매크로는 다른 영역에서도 그대로 적용되어 이름 충돌 위험이 있습니다.
코드 길이 증가 — 전처리 과정에서 코드가 확장되어 삽입되므로 전체 코드 크기가 커질 수 있습니다.
컴파일 타임 오류 미검사 — 매크로 확장 단계에서는 문법 오류 등을 확인하지 않습니다.
참고로, 매크로의 괄호 문제는 #define SQUARE(x) ((x) * (x))처럼 매개변수를 괄호로 감싸면 어느 정도 예방할 수 있지만, 근본적인 타입 검사 부재 등의 한계는 여전히 남아 있습니다. 이러한 이유로 현대 C/C++ 개발에서는 가능한 한 inline 함수나 일반 함수를 사용하는 것이 안전하고 권장되는 방식입니다.