SomeHeader.h

#ifndef _SOME_HEADER_
#define _SOME_HEADER_

// 헤더 내용들이 많이 있다.

#endif


OtherHeader.h

#pragma once

// ... 뭐 있겠지



두 가지 방식의 차이점이라든지 비교우위 등을 알고 싶어하는 이들이 많다.

짤막하게 짚고 넘어가자면 전자(SomeHeader)는 언어 차원의 표준이며 컴파일러가 항상 지원해야하는 믿을 수 있는 기능이고

후자(OtherHeader)는 일부 성능 좋은(?) 컴파일러만 지원하는 변종 기능이다.

변종인 만큼 후자의 방식은 전처리기가 아예 파일도 열어보지 않고 컴파일을 건너뛰고,

전자는 일단 파일을 열어보고 건너뛴다는 차이점을 가지며, 변종이 조금 더 속도에서 우세하다고 한다.



맞는 얘기들이었지만 사실 이젠 좀 철 지난 이야기들이다.

실제로 #ifndef 든 #pragma 든 둘 다 전처리기(Preprocessor) 지시자이며 컴파일을 하기 전에 먼저 처리되는 것들이다.

#ifndef 와 #endif (#else 라든지 #elif 도 좋겠다) 사이에 수백만줄 정도가 있다면 #pragma once 와 차이가 좀 벌어질 수 있으나

일반적인 기준에서 잘 짜여진 헤더파일(그 자체로 문서로 여겨질 수 있는 요약본 형식의)의 크기 안에서는

그럭저럭 무난하게 무시해줄 수 있다.
(물론 그렇다고 해서 그 헤더 파일이 수천번 include 되어도 무난하다는 소리는 절대 아니다)


중요한 것은 정말로 파일 전체가(꼭 헤더에 한정되지 않는다) 동일 obj 에서 한 번만 로딩된다면 #pragma once 도 괜찮겠지만

다른 조건들이 포함되어 있다면 #ifndef 를 활용하는 것이다. #ifndef 의 원래 용도를 잘 생각해보자.
(혹자는 #pragma once 가 표준이 아님을 들어 #ifndef 를 권하고 있으나 사실 가장 널리 사용되는 상위 컴파일러들은 모두 지원하고 있으므로 딱히 문제가 되진 않는다)

만약 헤더 파일이 수천줄 쯤 된다면, 그리고 그 헤더 파일을 많은 곳에서 include 한다면 #ifndef 보다는 #pragma once 를

쓰는 것이 확실히 전처리 속도에 도움이 된다.


감이 잘 안 오는 사람들을 위해 아래와 같은 스샷을 마련했다


 

대충 파일 구조는 위의 것을 보면 쉽게 알 수 있을 것이고

컴파일 결과를 그냥 IDE에서 컴파일해버리면 알기 어려우니 직접 명령어를 조작하여 컴파일을 시도해보는 것이 좋다.

원래 영어 IDE 를 사용하지만 스샷을 위해 한글을 마련했다. 왕친절한 것 같다.


 

 
<아 이렇게 친절할 수가.jpg> 



result.cpp 의 내용을 보자


 

드문드문 보이는 빈 공백들은 바로 전처리기가 #ifndef ~ #endif 같은 조건에 걸려 삭제해버린 줄들이다.
(물론 쓸모 없는 전처리기 구문 자체도 지우기 때문에 원래 3번 라인 밑에 나와야 하는 #ifndef _IFNDEF_ 같은 구문이 모두 빈줄로 대체되어 있다)


other.cpp 의 경우를 보아야 #ifndef 와 #pragma once 의 차이점을 확실히 알 수 있다.

other.cpp 는 22줄에서 보다시피 처음으로 ifndef.h 파일을 포함하였는데 이후 middle.h 에서 다시 한 번 포함한다(36줄)

그러나 앞서 이미 포함되어 있었으므로 모두 공백으로 대체되었다.

그러나 30줄에서 보다시피 other.cpp 는 pragmaonce.h 파일도 먼저 포함하였는데 이후 44번째 줄에서 보다시피

middle.h 가 선언한 #include "pragmaonce.h" 명령은 공백으로 대체되어 아예 포함조차 시도하지 않았다.

이것을 통해 #ifndef 와 #pragma once 의 실제 움직임을 조금은 따라가 볼 수 있는가?



#line 지시문에 대해서는 관심있는 사람들에 한해 찾아보도록 남겨두겠다.



그런데 주의할 점이 있다. 여기서 1회 포함 및 생성이란 얘기는 "파일 단위"에서의 이야기다.

그리고 이것이야말로 Unity Build 라는 기법이 왜 필요한가의 이유가 된다.


내가 심심해서 main.cpp 와 other.cpp 두 개를 만들지는 않았을 것이다.

우리는 보통 #ifndef (또는 #pragma once) 를 사용하면 헤더 파일을 전체 프로젝트에서 한 번만 include 할 것이라고

착각할 수 있는데(또는 별 신경 안 쓰고 넘어갈 수 있는데) 위에서 보다시피, 사실이 아니다.

한 번만 include 하는 것은 모두 오브젝트 단위에서의 이야기다.

오브젝트가 다르면 제 아무리 이전에 8만줄짜리 파일을 포함하여 컴파일을 이미 진행했다 하더라도

컴파일러는 다시 컴파일을 진행해버린다는 이야기다.

이런 짓을 하지 않기 위해 Unity Build 라는 스킬이 등장한 것이고 이와 관련해서는 서툰 내 글솜씨보다

훨씬 잘 된 자료가 있으므로 그것을 공유하며 이 포스팅을 마칠까 한다


http://www.slideshare.net/devcatpublications/ndc2010-unity-build




 


Posted by OOJJRS
,