선행처리기를 사용하는 이유
요약하면, 컴파일 전에 먼저 처리하고 싶은 것이 있기 때문이다.
C 코드를 실행 파일로 만들기 위해서는 선행처리 → 컴파일 → 링킹의 3단계를 거쳐야 한다.
여기서 가장 핵심적인 단계는 '컴파일'인데, 일종의 번역으로 생각하면 된다. C언어를 컴퓨터가 알아들을 수 있게 번역하는 것이다.
그리고 선행처리는 코드를 컴파일하기 전, 사용자가 정의한 내용을 일부 먼저 처리하는 과정이다.
종류
선행처리기 | 기능 |
#include | 파일 포함 |
#define | 매크로 정의 |
#if, #else, #elif, #endif | 조건부 컴파일 |
#include
JS/TS의 module import, Go의 pkg import와 유사한 개념이다.
다른 파일에 있는 코드를 사용하기 위해, 헤더 파일(*.h)을 함께 컴파일하려고 사용한다.
#include <경로|파일명>
#include "경로|파일명"
// 위와 같은 두 가지 형태로 사용 가능
#define
다른 언어/생태계의 .env 파일이나 config 파일과 유사한 개념인 것 같다.
매크로(macro) 자체는 '단순 치환되는 자료'를 말하는데, 상수와 함수를 정의할 수 있다.
방통대 교재에서는 매크로 함수를 정의하면 이런 장점이 있다고 한다.
1. 자료형 명시할 필요 없음
2. 한두 줄 정도의 간단한 함수는 일반 함수로 정의하는 것 보다 빠름
그러나 찾아보니 어지간하면 매크로를 쓰지 않는 것이 국룰인 것 같다.
상수의 경우는 const 나 enum을 사용하기를 추천하고, 함수는 그냥 정의하라는 의견이 대다수였다.
#if, #else, #elif, #endif
#if는 컴파일할 때 해당 코드를 포함시킬지 여부를 정의하는 기능이다.
조건문이 생길 때마다 코드에서 분기가 일어나기 때문에 프로그램의 성능이 저하된다.
때문에 아예 컴파일 전에 일부 조건문을 제거해 버리는 것이다.
#define을 굳이 사용해야 할 경우를 꼽자면 바로 #if를 사용하는 경우이다.
아래 예시를 보면 이해가 더 쉽다.
일반적인 조건문 if는 컴파일된 결과물에 조건문이 포함되지만, #if를 사용하면 컴파일 후 조건문이 사라지는 것을 알 수 있다.
// 컴파일 전
#include <stdio.h>
#define COND 1
void main() {
if (COND)
printf("조건 1\n");
else
printf("조건 %d\n", COND);
}
// 컴파일 후
void main() {
if (COND)
printf("조건 1\n");
else
printf("조건 %d\n", COND);
}
// 컴파일 전
#include <stdio.h>
#define COND 1
void main() {
#if COND
printf("조건 1\n");
#else
printf("조건 %d\n", COND);
#endif
}
// 컴파일 후
void main() {
printf("조건 1\n");
}