헤더파일(.h) 파일은 주료 함수선언과 전역변수 extern선언할 때 주로 들어간다. (물론 #define 같은 매크로도 들어간다.)
그리고 #include는 저번 글처럼 복사 붙여 넣기(확장)해주는 매크로이다.
헤더파일에 #define 같은 매크로를 다른 헤더파일에서도 사용을 해야 할 일이 있을 때, 양쪽 헤더 파일에 인클루드를 할 때가 있다.
예시코드 파일 3개를 보자
#include "b.h"
/* 코드 내용 생략 */
파일1 a.h
#include "a.h"
/* 코드 내용 생략 */
파일 2b.h
#include "a.h"
int main(void)
{
/* 코드 내용 생략 */
return 0;
}
파일 3 c.c
여기서 c.c 파일을 컴파일하게 되면 어떻게 될까?
- #include "a.h"에 의해서 a.h파일이 복붙 됨
- a.h파일이 복붙 된 코드에서 #include "b.h"에 의해서 b.h파일이 복붙 됨
- b.h파일의 코드에서 #include "a.h"에 의해서 a.h파일이 복붙 됨
- 2~3 과정의 반복
- 반복되는 #include 복사롤 인한 오류 발생 즉, 헤더가 꼬이는 문제가 생김
위와 같이 In file included from ./a.h:1: 과 In file included from ./b.h:1:가 계속 반복되다가 저절로 오류가 발생한다.
이와 같은 오류를 해결하는 방법이 2가지가 있는데 설명하겠다.
해결책(1) : 인클루드가 중첩되는 상황 자체를 피한다
헤더파일에는 #include를 가능하면 넣지 말고. c파일에만 넣어서 인클루드가 중첩되는 상황을 피할 수 있다.
위와 같은 코드는 b헤더에 a헤더에 있는 함수들을 전방선언하는 방식으로 해결할 수 있다.
그렇지만 항상 이렇게 전방선언을 직접 하다 보면 코드를 수정할 때 하나하나 수정을 안 하기 위해서 헤더파일을 작성하는 것인데, 실수를 할 여지가 생기게 된다.
그렇기에 이 방식은 좋다고는 할 수가 없다.
해결책(2) : 인클루드 가드(헤더가드)를 만든다
인클루드 가드란 인클루드를 할 때 헤더가 꼬이는 상황을 막기 위한 방식이다.
아까 전 코드를 인클루드 가드로 해서 만들어 보면
#ifndef A_H
#define A_H
#include "b.h"
/* 코드 내용 생략 */
#endif /* A_H */
파일 4 수정된 a.h
#ifndef B_H
#define B_H
#include "a.h"
/* 코드 내용 생략 */
#endif /* B_H */
파일 5 수정된 b.h
#include "a.h"
int main(void)
{
/* 코드 내용 생략 */
return 0;
}
파일 6 기존 c.c
이렇게 만들 수 있다. #ifndef라는 것은 매크로인데 '뒤에 있는 내용이 정의(#define) 되어있지 않은가?'를 나타내는 조건 매크로이다. 그래서 정의되어 있지 않다면 #endif 사이의 있는 내용을 복붙 해주게 된다.
이 방식을 차례대로 설명하자면
- #include "a.h"에 의해서 a.h파일이 복붙 됨
- a.h파일의 #ifndef A_H 즉, A_H가 정의된 적이 없으면 #endif 사이의 내용을 복붙 한다
- 그리고 다음 코드인 #define A_H로 A_H를 정의해 준다
- 다음 코드인 #include "b.h"로 b.h파일을 복붙 한다
- b.h파일의 #ifndef B_H 즉, B_H가 정의된 적이 없으면 #endif 사이의 내용을 복붙 한다
- 그리고 #define B_H로 B_H를 정의한다
- 그리고 다시 #include "a.h"를 불러온다
- a.h파일에서 #ifndef A_H에서 A_H가 정의되어 있으므로 #endif 사이의 코드는 지운다
- 인클루드 중첩 발생하지 않음
이 인클루드 가드를 통해서 헤더가 여러 번 인클루드 되는 것을 차단할 수 있다.
그리고 #define을 할 때 꼭 파일이름으로 해야 되는 건 아니지만 파일이름으로 해놓으면 가독성이 좋아서 어떤 파일에 인클루드 가드를 한지 알 수 있다.
그리고 #endif 뒤에도 주석을 넣는 이유도 마찬가지로 헤더파일의 인클루드 가드가 끝나는 위치를 쉽게 파악할 수 있기 때문에 넣어주자.
이는 포프선생님 피셜로 업계표준으로 쓰인다고 한다. 이런 방식을 고안해 낸 사람들이 진짜로 머리가 좋은 것 같다.
2023.01.09 - [POCU/COMP2200(C언어)] - [C]#include 의미 / 자료형 정리
출처 : POCU Academy COMP2200
'C언어 > C언어' 카테고리의 다른 글
[C언어]C언어에서 헤더파일이 필요한 이유?(헤더파일 필요성) (0) | 2023.02.16 |
---|---|
[C언어]C프로그램 빌드 과정(컴파일,링크,빌드의 차이) (0) | 2023.02.15 |
[C언어]#include <> 와 #include " " 차이 (0) | 2023.02.15 |
[C언어]암시적 형변환 C99표준(size_t(=unsigned int) 와 int 연산할 때 형변환포함) (0) | 2023.01.13 |
[C언어]size_t 자료형과 사용할 때 주의점(size_t VS unsigned int) (0) | 2023.01.12 |
댓글