우당탕탕 개발일지
[C언어] 전처리기 본문
#으로 시작하는 문장은 전처리기 지시자이다. 전처리기(preprocessor)는 보통 본격적으로 컴파일하기 전에 사전 작업을 하는 컴파일러의 일부분이다. #include는 소스 코드 안에 특정 파일을 포함시키라고 지시하는 명렁어이다. stdio.h와 같은 파일들은 헤더 파일이라고 불리며 컴파일러가 필요로 하는 정보를 가지고 있다. 전처리기 지시자 끝에는 세미콜론(;)을 붙이면 안 된다.
1. #define, #undef
✅ #define
#define은 단순 매크로를 정의할 때 사용하는 형태 정의 전처리문이다. 상수를 정의하려고 할 때 가장 많이 사용하는 지시자로 ‘메크로’라고 부른다. 매크로는 두 가지 종류가 있으며, 사용될 때 형태가 다르다.
- 객체형 매크로
- 함수형 매크로
✅ 객체형 매크로
#define DATE 0327
- #define [매크로 이름] [값]
- 보통 매크로 이름은 대문자를 많이 사용한다.
- ; (세미콜론)을 사용하면 안된다.
변수 선언과의 차이
메모리를 할당하느냐 안하느냐의 차이이다. 변수를 선언하면 변수 선언 크기만큼 메모리를 사용하지만, #define을 사용하면 메모리를 할당하기 전에 정의된 단어를 모두 해당하는 값으로 바꾸고 시작하기 때문에 메모리를 할당하지 않는다.
✅ 함수형 매크로
함수형 매크로는 #define 지시문을 사용하되, 매크로 이름 바로 뒤에 괄호를 붙여서 정의한다.
#define CLAC(x, y)((x)*(y))
printf("%d\n", CALC(2, 4)); // 결과: 8
매크로 정의는 기본적으로 한 줄에서 끝나지만, 백슬래시(\) + 줄바꿈을 사용하면 여러 줄로 쓸 수 있다.
#define WARN_IF(EXP) \
do { if (EXP) \
fprintf(stderr, "Warning: " #EXP "\n"); } \
while (0)
WARN_IF(x == 0);
do { . . . } while (0) 형식은 매크로를 함수처럼 사용하기 위한 방식으로, 세미콜론(;)을 붙여도 문제가 없다.
✅ 가변 인자 매크로
가변 인자 매크로는 함수처럼 인자 개수를 가변적으로 받을 수 있는 매크로이다.
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
- . . . 은 가변 인자를 의미한다.
- __VA_ARGS__는 . . . 에 해당하는 실제 인자들이 들어가는 자리이다.
다음 매크로들은 C/C++ 언어 표준에서 정의된 매크로들로, 대부분의 컴파일러에서 사용할 수 있다. 매크로 이름은 항상 __로 시작하며, 전처리 시 자동으로 정의된다.
🔹 __FILE__
- 현재 소스 파일의 이름을 문자열 상수로 반환
- 실제로 전처리기가 열었던 전체 경로가 들어간다.
printf("File: %s\n", __FILE__);
// → File: "/usr/local/include/myheader.h"
🔹 __LINE__
- 현재 소스 코드의 **줄 번호(line number)**를 정수 상수로 반환
printf("Line: %d\n", __LINE__);
// → 현재 줄 번호 출력
🔹 사용 예시
fprintf(stderr, "Internal error at %s, line %d\n", __FILE__, __LINE__);
#include가 발생하면 포함된 파일 기준으로 __FILE__, __LINE__이 바뀐다. 디버깅 시 오류 위치 출력 등에 자주 사용된다.
🔹 __func__, __FUNCTION__ (함수 이름)
- 현재 함수 이름을 문자열로 제공
void test() {
printf("Function: %s\n", __func__); // → "test"
}
🔹 __DATE__
- 컴파일(전처리) 시점의 날짜를 문자열로 반환
printf("Build date: %s\n", __DATE__);
🔹 __TIME__
- 컴파일(전처리) 시점의 시간을 문자열로 반환
printf("Build time: %s\n", __TIME__);
✅ #undef
#undef는 이미 정의된 매크로를 없애는 역할을 한다.
#undef DATE
- #undef [정의된 매크로 이름]
2. #include
✅ #include
#include 는 대표적인 파일 처리 전처리문으로, 외부 파일을 읽어서 내부 소스 코드로 포함시키려고 할 때 사용할 수 있다.
✅ #include <파일명.h>와 #include “파일명.h” 차이점
#include <stdio.h>
- 해당 위치에 stdio.h라는 파일을 포함시키겠다는 의미이다.
#inlude "header.h"
- 직접 작성한 사용자 정의 헤더 파일을 추가할 수도 있다.
기본적으로 <>로 정의하면 컴파일러의 표준 포함 디렉터리에서 찾게 되며, ““로 정의를 하면 현재 디렉토리를 기준으로 파일을 찾게 된다.
참고
#include "C:\test\abc.h"
- 해당 드라이브 경로 내에서 찾음
#include "..\abc.h"
- 현재 소스 파일의 상위 폴더 내에서 찾음
3. #if, #elif, #endif
전처리기는 { }를 사용하지 않기 때문에 #endif를 사용하여 조건문의 끝을 알린다.
✅ #if, #elif, #endif
#if 조건1
조건1이 참 일때
#elif 조건2
조건1이 거짓이고 조건2가 참 일때
#else
조건 1,2가 거짓일때
#endif
- #if로 조건문의 시작을 알린 뒤 #endif로 조건문의 끝을 알린다.
- #elif는 else if의 줄임말이다.
- #elif, #else는 필요하지 않으면 생략이 가능하다.
4. #ifdef, #endif
✅ #ifdef, #endif
#ifdef(= if define)는 지정된 매크로가 정의되어 있으면 발생하는 전처리기이다.
#ifndef(= if not define)는 #ifdef의 반대로, 매크로가 정의되어있지 않으면 발생하는 전처리기이다.
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
// 내용
#endif
- 매크로가 정의되어 있다면 문장들 A를 컴파일하고, 그렇지 않다면 문장들 B를 컴파일한다.
- 중복 정의를 피하기 위해 사용한다.
5. #error
✅ #error
- 사용자가 직접 설정해준 에러 메세지를 출력하고, 전처리 과정에서 컴파일을 중지시키도록 해준다.
- #error 전처리기문과 조건부 처리문을 함께 사용하면 특정 조건에서는 컴파일을 하지 않고 에러를 표시하도록 해준다.
※ 참고

컴파일은 전처리 과정, 컴파일 과정, 어셈블리 과정, 링킹 과정의 총 4 단계로 진행된다.
'Server > Linux, C' 카테고리의 다른 글
| [C언어] Thread (4) | 2025.06.25 |
|---|---|
| [C언어] Makefile / GDB (0) | 2025.05.25 |
| [Linux] 리눅스 파일과 파일 시스템 (1) | 2025.05.11 |
| [C언어] 문자열 (feat. strcpy, strtok_r 활용 예제) (0) | 2025.05.11 |
| [C언어] 기본 입출력 및 비트 연산자 (0) | 2025.05.11 |