헤더는 선언을 공유하는 곳이고 include guard는 그 선언이 여러 번 들어오는 것을 막는 장치입니다.
- 헤더에 함수 본문을 넣어도 되는지 헷갈린다
extern과 정의를 어디에 둬야 하는지 다시 확인하고 싶다- include guard가 왜 필요한지 빠르게 떠올리고 싶다
숏컷 코드
/* state.h */
#ifndef STATE_H
#define STATE_H
extern int g_count;
void reset_count(void);
#endif문법
헤더는 다른 .c 파일이 알아야 하는 선언과 타입 계약을 공유하는 곳입니다. 반대로 실제 함수 본문과 전역 변수 정의는 .c에 두는 편이 기본입니다.
C는 파일별로 따로 컴파일합니다. 다른 파일의 함수나 타입을 쓰려면 "미리" 그 모양을 알아야 합니다.
/* math_utils.h */
typedef struct {
double x;
double y;
} Point;
double distance(Point a, Point b);이 헤더를 main.c, renderer.c가 같이 include하면 둘 다 같은 인터페이스를 공유합니다.
구성 요소
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
typedef struct {
double x;
double y;
} Point;
double distance(Point a, Point b);
#endif헤더가 헤더를 포함하는 구조에서는 같은 내용이 여러 번 들어오기 쉽습니다. include guard가 없으면 타입 재정의나 선언 충돌이 바로 납니다.
#pragma once도 비슷한 역할이지만, 가장 기본적인 설명은 include guard 기준으로 익혀 두는 편이 안전합니다.
전역 변수도 같은 원리입니다. 헤더에는 extern 선언만 두고, 실제 정의는 .c 파일 하나에만 둡니다.
/* state.h */
extern int g_count;
/* state.c */
int g_count = 0;자주 실수하는 패턴
헤더에 정의를 넣는 경우입니다.
/* bad.h */
int counter = 0; // 정의
int add(int a, int b) { // 정의
return a + b;
}이 헤더를 두 .c 파일이 include하면 링크 단계에서 multiple definition이 납니다.
체크포인트
- 헤더는 선언
.c는 정의- 전역 변수 공유는 헤더에
extern - 중복 포함 방지는 include guard
- 작은 도우미만
static inline
주의할 점
헤더에 함수 정의나 전역 변수 정의를 넣으면 "컴파일은 되는데 링크에서 터지는" 경우가 많습니다. C에서 헤더 문제는 보통 전처리 단계가 아니라 링크 단계에서 더 크게 드러난다는 점을 기억해 두는 편이 좋습니다.
참고 링크
1 sources