중복 컴파일 방지를 위해 자주 쓰이는 전처리기 지시자들에 대해 비교해 보고자 한다.



1) #ifndef


먼저 다음과 같은 코드가 있다고 하자.


First.h

#ifndef _FIRST
#define _FIRST

class First
{
};
#endif

Second.h

#ifndef _SECOND
#define _SECOND

#include "First.h"

class Second
{
};
#endif

Main.cpp

#include "First.h"
#include "Second.h"

void Main()
{
}


Main.cpp 를 컴파일 해보면 #include 의 작동방식에 따라

그 파일의 코드가 그대로 복사될 것이다.


#ifndef _FIRST
#define _FIRST

class First
{
};
#endif

////////////////////////////////

#ifndef _SECOND
#define _SECOND

#include "First.h"

class Second
{
};
#endif

////////////////////////////////

void Main()
{
}


위와 같이 되고 Second 에서 또 한번 #include "First.h" 를 읽게 될 것이다.

그 결과로 ,


#ifndef _FIRST
#define _FIRST

class First
{
};
#endif

////////////////////////////////

#ifndef _SECOND
#define _SECOND

#ifndef _FIRST
#define _FIRST

class First
{
};
#endif

class Second
{
};
#endif

////////////////////////////////

void Main()
{
}


위의 코드와 같이 Main.cpp 에는 First.h 이 2번 복사되는 결과를 볼 수 있다.


결론을 내리자면, #ifndef 의 방식으로 중복 컴파일을 피하는 것은

#include 명령어를 사용한 횟수 만큼 전처리기가 그 파일을 복사해오고,

복사해 온 코드 상단에 작성된 #ifndef 구문을 읽고 컴파일 여부를 확인 한다는 것이다.


이렇게 결론을 지으면 

'그런데도 왜 이 방식을 써서 중복 컴파일 방지를 하냐 ?!'

라고 할 수 있다. 물론 장점도 존재하고 포스팅 마무리할 때쯤 언급하겠다.




2) #pragma once


그런데 나는 - pragma - 라는 단어가 대체 무슨 뜻인지 궁금해서 찾아보았다.



짜증. 괜히 맛있는 치킨만 먹고 싶어졌다.

그냥 컴파일러 지시자? 정도로만 이해해야겠다.


구글에 검색해도 pragma 가 뭐 하는 녀석인지만 나와있지,

정작 pragma 라는 단어 자체의 뜻에 대해서는 잘 안 나오는 듯_-_



어쨌든 잡소리였고 다시 중복 컴파일 방지를 위한 #pragma once 명령어로 돌아가자.


이 지시자가 의미하는 바는 '1번만 컴파일 하겠다' 라는 뜻으로 알고 있다.

msdn 에 따르면 (http://msdn.microsoft.com/en-us/library/4141z1cx(v=vs.80).aspx)


Pragma 지시자의 토큰 값으로 들어갈 수 있는 once 키워드 : 
Specifies that the file will be included (opened) only once by the compiler when compiling a source code file.

Remark : This can reduce build times as the compiler will not open and read the file after the first #include of the module.


아까 말한 것과 다를 바 없고, 이게 전부다. 

#ifndef 과 다르게 include 로 인해 여러 번 파일을 열어서 읽는 것이 아니라서 빌드 타임을 감소시킬 수 있다는 점.




3) 정리


#ifndef

- 앞서 보았듯이 헤더 파일을 여러 번 include 하게 되면 define 여부를 계속 체크해야 되기 때문에

컴파일 단계 중에서 파일 해석 단계의 속도가 #pragma once 에 비해서 다소 느리다고 할 수 있다.

하지만 장점을 꼽자면 전처리기 지시자(Preprocessor directive)라서 모든 컴파일러에서 동작한다는 점이다.


#pragma once :

- 1번만 컴파일 하고 그 뒤로부터는 동일한 파일의 경우, 읽기조차 하지 않는다. 그래서 파일 해석 단계의 속도가

#ifndef 보다는 빠르다. 하지만 아까 사전적 의미를 찾아봤을 때, 자세히 보면 'A compiler directive' 라고 적혀있다.

컴파일러 지시자로 특정 컴파일러에서만 동작하는 지시자이며 Visual C++ 5.0 이상에서만 동작한다고 한다.



얼핏 속도면에서 보면 #pragma once 가 좋아보일 수 있으나 

거대 프로젝트가 아닌 이상 속도에서 큰 차이를 볼 수 있을까? 하는 의문이 든다.


그리고 안정성(호환성)과 범용성을 고려한다면 #ifndef 방식을 택해야 할 것이다.




4) Reference


http://ace01kr.tistory.com/entry/%ED%97%A4%EB%8D%94%ED%8C%8C%EC%9D%BC-%EC%A4%91%EB%B3%B5%EB%B0%A9%EC%A7%80-pragma-once-vs-ifndefendif


http://neodreamer-dev.tistory.com/310


http://msdn.microsoft.com/en-us/library/t22e924w(v=vs.80).aspx


'Programming > C++' 카테고리의 다른 글

dynamic_cast 연산자  (0) 2014.10.26
정적 바인딩(Static binding) vs. 동적 바인딩(Dynamic binding)  (0) 2014.08.19
by kelicia 2014. 8. 25. 19:21