매크로와 선행처리기
실행파일이 컴파일과 링크의 과정을 거치는데 컴파일 이전에 선행처리 과정을 거친다.
▶ 선행처리 → 컴파일 → 오브젝트 파일 → 링크 → 실행 파일
※ 컴파일 과정에 포함해서 표현하기도 한다.
한편으로는 컴파일러에 따라서 전처리 과정은 전처리기(preprocessor)라는
별도의 프로그램으로 수행하기도 한다.
※ 소스코드가 선행 처리기를 거쳐도 별도의 파일이 생성되는 것은 아니다.
소스파일을 유지 하며, 선행처리 명령문대로 소스코드의 일부를 치환할 뿐이다.
- 컴파일: 오브젝트 파일 생성
- 링커: 실행파일 생성
#include <stdio.h>
#define NAME "TEST"
#define PRINT_ADDR puts("주소: xxx-xxx");
#define SQUARE(X) X*X
int main(void){
printf("%s \n", NAME); // TEST
PRINT_ADDR; // 주소: xxx-xxx
printf("%d", SQUARE(-5)); // 25
}
매크로로 정의되어 있는 부분이 치환된다.
매크로 함수는 성능을 높일 수 있지만 사용할 때 주의해야 할 것이 있다.
Q) #define SQUARE(X) X*X 부분에서 SQUARE(3 + 2)로 호출하면 결과는 어떻게 될까?
A) 원하는 결과는 (3+ 2) * (3 + 2) = 25이지만 실제 결과는 3 + 2 * 3 + 2 = 11이 됩니다.
이렇게 처리되는 이유는 (3 + 2)가 먼저 연산을 하고, 그 연산결과를 가지고 선행처리 되지 않기 때문이다.
※ 일반적인 함수라면 결과값을 가지고 인자가 전달된다.
이와 같은 경우를 처리하기 위해서는
- SQUARE((3+2))로 호출
- 매크로 정의 자체를 #define SQUARE(X) (X)*(X) 모두 괄호 처리 해버리는 것이다.
Q) 두 줄 이상 사용한다면
매크로는 한 줄 정의가 원칙이기 때문에
가독성을 위해 두 줄 이상에 거쳐서 정의할 경우
백슬러쉬(\) 이용하면 된다.
#define SQUARE(X) \
((X)*(X))
매크로 함수 장단점
[장점]
일반 함수라면 함수를 스택 메모리에 할당, 매개변수 전달 등
빈번한 호출이 발생할 수 있지만 매크로 함수는 선행 처리기에 의해
호출 문장을 대신하므로 실행 속도가 빠르다.
또한, 자료형에 따라서 별도 함수를 정의하지 않아도 된다.
// 일반 함수
int DiffABS(int a, int b){
if(a > b) return a-b;
else return b-a;
}
// 매크로 함수
#define DIFF_ABS(X,Y) ((X)>(Y) ? (X)-(Y) : (Y)-(X))
[단점]
정의하기 까다롭다.
디버깅하기가 쉽지 않다.
즉, 매크로 함수는
작은 크기의 함수나 호출의 빈도수가 높은 함수에 유용하다고 할 수 있다.
'프로그래밍 언어 > C 언어' 카테고리의 다른 글
[C] 포인터 변수 개념 (15) | 2025.03.30 |
---|---|
[C/C++] [전처리기] 헤더파일(.h) 만들어서 include 하기 (2) | 2025.01.09 |
[C/C++] const 키워드 (1) | 2024.12.30 |
[C/C++] #include "헤더파일" & #include <헤더파일> (1) | 2024.12.25 |
[C/C++] 지역변수와 전역변수와 레지스터 변수 (1) | 2024.12.22 |
댓글