김윤수의 이상계를 꿈꾸며  
대문으로
도라홈스쿨 | 태그 | 지역태그 | 미디어로그 | 방명록 | 관리자 | 새글 쓰기   
 
고수들이 절대 가르쳐 주지 않는 C/C++ 프로그래밍 팁 #1 - include guard
[공지1] 영문 블로그를 옮겼습니다. 주소는 http://codeguru.textcube.com 입니다. 새로운 내용을 올리진 않고, 당분간 이곳에 올린 내용들을 영어로 옮기는 작업을 할 것 같습니다. 제 영문 블로그도 많이 응원해 주세요~
[공지2] 최근 네이버에서 공개한 나눔고딕 글꼴을 적용했습니다. 나눔고딕이 없으신 분은 맑은 고딕, 윤디자인고딕, AppleGothic 순으로 적용됩니다. 나눔고딕이 없으신 분은 여기에서 다운 받으시면 됩니다
[공지3] 제 글을 복사하고 싶으신 분이나 저작권 정보를 알고 싶으신 분은 이 글을 읽어 보세요
[공지4] 각종 Open Source License 번역 시작



(podics.com 에 올려 놓은 이 글에 대한 podcast도 같이 연결해 놓았습니다. 플레이 버튼을 누르고 아래 글을 읽으시면 이해에 도움이 될 것입니다)

기존에 제가 써 오던 C++ 이야기 시리즈와는 별도로 얘기하고 싶은 것이 있어서 새로운 시리즈로 "고수들이 절대 가르쳐 주지 않는 C/C++ 프로그래밍 팁"을 시작해 볼까 합니다. 시리즈 이름이 너무 길어서 고절가주팁이라고 줄여서 말해렵니. ^^ 얼마나 많이 나올 수 있을지는 모르겠지만 어찌 됐든 또 쭉~ 한 번 가보는 거죠.

첫번째 팁으로는 헤더 파일이 중복 포함되는 걸 방지하는 법에 대해 설명드릴까 합니다. 다 알고 계신다구요 ? 예~ 그러시겠죠. 알고 계신다면 C/C++ 프로그래밍 고수임에 틀림이 없습니다. 그러시다면 아래까지 쭉~ 읽어 보시고 잘못된 부분은 없나 추가할만한 얘기는 없나 보고 댓글 남겨 주시는 센~스! 부탁드리겠습니다.

제가 첫 회사에 입사하고 나서 처음으로 프로젝트를 할 때였습니다. 그 때, 누가 요구 분석하고, 구조 설계하고, 상세 설계하고 가이드해 줄 선배가 없었습니다. 제가 처음으로 해 본 프로젝트이자 회사도 처음으로 해 본 프로젝트였으니까요(저의 첫 회사는 조그만 중소기업이었습니다). 거의 그냥 맨땅에 헤딩하다시피 하면서 열정과 패기만으로 프로젝트를 수행하고 있었습니다.

정말 한참 동안 코딩을 하고 나서(머리 속으로 설계하고 바로 코딩에 들어갔죠. 좋은 방법은 아닙니다. 오해 없으시길...), 처음으로 컴파일을 시도했습니다. 무식하면 용감하다고 제 기억으로 거의 이삼만 라인 이상을 작성하는 동안 한 번도 컴파일하지 않다가 처음으로 그것도 보무도 당당하게 컴파일을 시도했습니다. 이제 컴파일만하고 실행시켜 보면 된다. 제 머리속에서는 완벽하게 돌았으니깐 문제 없을거야하며 엔터를 치는 순간 아니! 이게 웬 일입니까. 정말 수 많은 에러들이 수십 페이지가 넘도록 발생하다가 결국 컴파일러가 에러가 너무 많아서 컴파일할 수 없다고 포기해 버리는 것 아니겠습니까 ?

그 수 많은 에러를 보는 순간 어찌나 눈 앞이 캄캄하던지... 개발해 보면서 컴파일 에러에 압도된 적이 있으신가요 ? 우와~ 정말 미치겠더군요. 저는 그 때 정말 에러 메시지에 압도 돼 버렸습니다. 순간 개발자라는 직업이 나를 거부하나 보다 지금이라도 직종 전환할까하고 생각도 했습니다. 한동안 정신 못 차리고 있다가 겨우 마음을 추스리고 나서 이틀 내내 그 많은 컴파일 에러들 잡느라 고생 고생했습니다. 거짓말 아닙니다. 정말 컴파일 에러만 없애는데 이틀이 꼬박 걸렸습니다.

그런데 그 중에 제일 많은 에러를 발생시킨 게 어떤 거였는지 상상이 되십니까 ? 그건 바로 오늘의 주제인 헤더 파일 중복 포함 때문이었습니다. 그때 저는 프로그래밍 경험이 일천한지라, 그리고 누가 가르쳐 주는 사람도 없는지라 헤더 파일이 중복 포함되는 걸 방지하는 방법을 쓰는 게 아니라 헤더 파일 포함 순서를 바꿔보고, 코드를 이리 저리 옮겨 보고 하는 식으로 정말 죽을 똥 살 똥하면서 그 많은 컴파일 에러를 잡아 냈습니다. 정말 인간 승리였죠.

그땐 정말 악몽 같았지만 그런 경험이 있기 때문에 오늘 이런 글을 쓸 수 있는 것 아니겠습니까 ? 제가 이렇게 장황하게 제 개인적인 경험 이야기를 늘어 놓는 건 이 팁이 사소하게 느껴질 수도 있지만 정말 중요한 팁이라는 걸 말씀드리고 싶었기 때문입니다. 아마 보통은 제가 말씀 드리려는 이 팁이 회사의 Coding Standard 에 들어 있어서 그걸 따르면 제가 겪었던 문제는 발생하지 않을 것입니다. 어떻게 보면 그런 문제를 해결한 경험이 이미 회사의 무형 자산으로 쌓여 있는 것이겠죠. 아니면 이미 경험한 선배들의 머리 속에 있거나요.

자! 그럼 제가 경험한 문제를 여러분도 한 번 실제로 경험해 볼 수 있도록 다음 코드를 작성한 후 컴파일 해 보시겠어요 ?

// hdr1.h 의 내용
class DummyBase {
private:
  int _i;

public:
  DummyBase(int i): _i(i) {
  }

  int Get() {
    return _i;
  }

  void Set(int i) {
    _i = i;
  }
};

// hdr2.h 의 내용
#include "hdr1.h"              // hdr1.h 을 여기서 include 하고 있습니다

class Dummy: DummyBase {
public:
  Dummy(int i): DummyBase(i) {
  }

  int operator() () {
    return Get();
  }

  int operator() (int multi) {
    return Get() * multi;
  }
};

// tips1.cpp 의 내용
#include "hdr1.h"           // tips1.cpp 에서도 hdr1.h 을 include 하네요
#include "hdr2.h"

int
main()
{
  DummyBase db(200);
  Dummy d(100);
}


이미 중복 포함 문제가 어떻게 발생하는지를 아시는 분은 어떤 에러가 어떤 지점에서 발생될지 상상이 되시죠 ? 제가 사용하는 컴파일러로는 다음과 같은 에러가 발생하네요.

c:\documents and settings\김윤수\my documents\visual studio 2005\projects\tips\tips1\hdr1.h(1) : error C2011: 'DummyBase' : 'class' type redefinition
        c:\documents and settings\김윤수\my documents\visual studio 2005\projects\tips\tips1\hdr1.h(1) : see declaration of 'DummyBase'
c:\documents and settings\김윤수\my documents\visual studio 2005\projects\tips\tips1\hdr2.h(3) : error C2504: 'DummyBase' : base class undefined
c:\documents and settings\김윤수\my documents\visual studio 2005\projects\tips\tips1\hdr2.h(5) : error C2614: 'Dummy' : illegal member initialization: 'DummyBase' is not a base or member
c:\documents and settings\김윤수\my documents\visual studio 2005\projects\tips\tips1\hdr2.h(9) : error C3861: 'Get': identifier not found
c:\documents and settings\김윤수\my documents\visual studio 2005\projects\tips\tips1\hdr2.h(13) : error C3861: 'Get': identifier not found
Build log was saved at "file://c:\Documents and Settings\김윤수\My Documents\Visual Studio 2005\Projects\Tips\Tips1\Debug\BuildLog.htm"
Tips1 - 5 error(s), 0 warning(s)


어때요 ? 보기만 해도 그냥 갑갑하시죠 ? 제가 표시한 파란 부분을 보니 'DummyBase' 클래스가 재정의됐다고 하네요. 그 다음 에러들은 다 첫번째 에러 때문에 파생된 에러들입니다. 이런 에러 패턴이 헤더 파일이 중복 포함되어 발생하는 것이라는 걸 알고 있는 사람은 해결하기가 쉽지만 잘 모르는 사람은 문제를 해결하는데 한참이 걸리게 마련입니다. 에러 메시지 자체가 클래스가 재정의됐다고만 말하고 있기 때문에 헤더 파일이 중복 포함되었다는 데까지 생각이 미치기 어려고, 게다가 그 다음에 딸려 오는 에러들은 진짜 문제점(root cause)를 찾는 데 방해만 되기 때문입니다.

자~ 그럼 이 문제를 어떻게 해결할 수 있을까요 ? 제가 생각할 수 있는 방법은 다음과 같습니다.

1) hdr1.h, hdr2.h 의 내용을 모두 tips1.cpp 로 모두 옮긴다. ^^;
2) hdr1.h 의 내용을 hdr2.h 로 옮기고 tips1.cpp 에서는 hdr2.h 만 include 한다.
3) 다른 건 다 그대로 놔두고 tips1.cpp 에서 hdr1.h 은 include 하지 않는다.

이것말고 다른 방법이 떠 오르시나요 ? 위 방법들은 여기에 제시된 코드에만 적용할 수 있는 임시방편적인 방법이라고 할 수 있구요, 좀 더 근본적인 방법은 모든 헤더 파일을 다음과 같이 작성하는 겁니다.

// 헤더 파일의 제일 첫 부분
01: #ifndef HDR_H     // 헤더 파일명을 대문자한 매크로가 정의되어 있지 않으면
02: #define HDR_H     // 헤더 파일명 매크로를 정의한다

......                // 헤더 파일 본 내용이 여기 들어갑니다

03: #endif            // ifndef HDR_H 에 매치됩니다


위와 같이 헤더 파일을 작성하게 되면 다음과 같은 과정이 일어나게 됩니다. 컴파일러와 역지사지해서 생각해 보겠습니다.

1. 처음으로 헤더 파일이 포함될 때, 컴파일러(좀 더 정확히 말하면 프리프로세서)가 01 라인을 만나게 되면 HDR_H 매크로가 정의되어 있지 않으므로 02 라인을 해석하게 됩니다.
2. 02 라인을 만나면 이제 HDR_H 매크로를 정의하게 됩니다.
3. 다음에 다시 같은 헤더 파일이 포함될 때는 HDR_H이 정의되어 있기 때문에 모든 헤더 파일의 내용을 스킵하게 됩니다. 즉, 포함되지 않는 효과가 생기게 됩니다.

자~! 그럼 여기 예제를 다시 수정한 후에 컴파일 해 볼까요 ?

// hdr1.h 의 내용
#ifndef HDR1_H
#define HDR1_H


class DummyBase {
private:
  int _i;

public:
  DummyBase(int i): _i(i) {
  }

  int Get() {
    return _i;
  }

  void Set(int i) {
    _i = i;
  }
};

#endif

// hdr2.h 의 내용
#ifndef HDR2_H
#define HDR2_H


#include "hdr1.h"              // hdr1.h 을 여기서 include 하고 있습니다

class Dummy: DummyBase {
public:
  Dummy(int i): DummyBase(i) {
  }

  int operator() () {
    return Get();
  }

  int operator() (int multi) {
    return Get() * multi;
  }
};

#endif

다시 컴파일해 보시면 에러가 발생하지 않는 걸 확인하실 수 있을 겁니다. 이해가 되시나요 ? 아마 요즘 대부분의 개발 조직에서 이 정도의 팁은 Coding Standard 로 가지고 있지 않을까 합니다. Coding Standard 에 왜 그런 항목이 있었는지를 이해하실 수 있다면 더 좋겠지요. 이유는 헤더 파일이 중복 포함되어 발생하는 컴파일 에러를 방지하기 위한 목적입니다.

여러분 컴퓨터에 설치되어 있는 헤더 파일을 열어 보면 위와 같이 헤더 파일이 중복 포함되는 걸 방지하기 위한 방법을 사용하고 있는 걸 확인하실 수 있을 겁니다.

그럼, 이번 글은 이 정도로 마무리 하고, 다음에는 C/C++ Mixed Programming 기법에 대해 설명드리도록 하겠습니다. 고절가주팁이 쭉~ 갈 수 있도록 많은 관심 부탁드립니다. 여러분이 알고 있는 팁을 트랙백이나 댓글로 좀 알려 주시면 더할 나위 없이 좋겠네요. 그리고, 혹시 Podcast 로 들으신 분들은 느낌이 어떤지, 이해에 도움이 되는지 댓글로 좀 남겨 주시면 감사하겠습니다.

제 글이 유익하셨다면 오른쪽 버튼을 눌러 제 블로그를 구독하세요. ->
블로그를 구독하는 방법을 잘 모르시는 분은 2. RSS 활용을 클릭하세요.
RSS에 대해 잘 모르시는 분은 1. RSS란 무엇인가를 클릭하세요.


제 글이 유익하셨다면 오른쪽 버튼을 눌러 제 블로그를 구독하세요. ->
블로그를 구독하는 방법을 잘 모르시는 분은 2. RSS 활용을 클릭하세요.
RSS에 대해 잘 모르시는 분은 1. RSS란 무엇인가를 클릭하세요.

마지막으로 제 글이 유익하셨다면 과감하게 추천 버튼 한방 부탁드립니다 ^^

Tag : , , , , , , , , , , , , ,


BLOG main image
이상계는 이쪽에 속해있지 않고 저쪽에 속해 있다. 이쪽에 사는 우리는 이쪽에 머무르지 않고 저쪽을 꿈꾸며 살아야 한다. 여기 오는 모든이들이 저쪽의 충만함을 이쪽에서의 매일의 삶에 경험할 수 있기를... E-mail: (yesarang) at (yahoo.co.kr)
 블로그 구독



meet me at meet me at me2DAY
E-mail 주소를 입력하세요:


 블로그 검색
Google
 Notice
me2day 개설했습니다.
블로그 스킨 바꾸었습니다
제 블로그의 성격
 분류
분류 전체보기 (341)
IT동향 (29)
사회동향 (4)
기술정리 (10)
개인 (17)
기타 (28)
기독교신앙 (1)
S/W개발 (110)
블로깅 (13)
리뷰 (8)
구글이야기 (9)
인터넷오늘은 (108)
독서 (3)
 태그 목록
인터넷오늘은 북마크 c++ 프로그래밍 sw개발 SW 개발 블로그 구글 SW 프로그래밍팁 c Programming Language S/W 개발 cpp 네이버 고수 고수팁 검색 고절가주팁 블로깅 IT 전략 iPhone 리뷰 다음 블로거 Programming Technology RSS
 달력
«   2009/07   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
 최근글
C++ 이야기 서른번째: boost::.. (4)
김윤수의 인터넷 오늘은 - 200..
김윤수의 인터넷 오늘은 - 200..
김윤수의 인터넷 오늘은 - 200.. (1)
C++이야기 스물아홉번째: Port..
 최근 댓글
그러게요. 저도 쓰면서 성능이..
김윤수 - 21:17
어느새 다녀갔네?
김윤수 - 21:15
아는대로 써 보는 거랑, 실제..
eslife - 07/01
좋은거 하나 배우고 갑니다. :)
파다기 - 07/01
전 미국에서 회사를 다녀서 그..
violino - 06/26
 최근 트랙백
TR1을 이용한 C++에서의 정규..
김재호의 디지털보단 아날로그
항목 39 : 가상 함수는 비공용..
최익필의 이름없는 블로그
죠커의 생각
jokka's me2DAY
검색 어뷰징 패턴 및 필터링..
made by 서보성
김윤수의 알림
yesarang's me2DAY
 Archive
2009/06
2009/01
2008/12
2008/11
2008/10
2008/09
2008/08
2008/07
2008/06
2008/05
2008/04
2008/03
 링크 모음
art.oriented
kkamagui 프로그래밍 세상
Monaca
Sutter's Mill
Yesarang's Blog[제 영문 블로..
[개인] Chester's Blog
[개인] Homo Scriptus
눈에 보이는 소프트웨어
류광의 번역 이야기
사진찍는 프로그래머
서광열의 프로그래밍 언어 이..
주네의 열린 소프트웨어
퓨처워커들의 u-Platform 이야기
필넷의 IT이야기
 방문자 통계
Total : 383,649
Today : 95
Yesterday : 29

믹시