친절한 그리고 불친절한 컴파일러 에러 메시지들

컴파일러 에러 메시지들 중에서 명백한 것도 많지만 난해한 것도 많았다. Visual Studio에 있는 C/C++ 컴파일러 메시지 중 난해한 것들 중 몇 가지들은 이제 꽤나 친절한 메시지로 바뀌었다. 몇 가지 대표적인 컴파일러 에러 메시지에 대해서 이야기 해보자.


첫 번째:

Fatal error C1010: unexpected end of file while looking for precompiled header.
Did you forget to add '#include "stdafx.h"' to your source?

초보자들이 겪었던 대표적인 VC++의 에러 메시지. 그러나 보다시피 더 이상 이 메시지는 난해하지 않다. 친절하게 "stdafx.h"를 빠뜨렸는지 알려주고 있다. Visual Studio에서 C/C++ 프로젝트들은 기본적으로 precompiled header를 쓰도록 되어있다. 그리고 이 precompiled header의 기본 이름은 stdafx.h (.h는 컴파일 단위가 아니므로 stdafx.cpp를 통해 미리 컴파일이 됨) 이다. 그래서 stdafx.h를 다른 소스 파일에서 #include하지 않으면 말 그대로 "precompiled header를 찾는 도중 예상치 못한 파일의 끝을 발견하였음" 이라고 뜨는 것이다. 그런데, 이건 VS 2005에서 뜨는 에러 메시지고 그 이전에는 다소 불친절 했다. 그래서 많은 초보자들이 당황하기도 하였다. VS.NET 2003까지는:

fatal error C1010: unexpected end of file while looking for precompiled header directive

라고 떴었다. "directive"라는 다소 초보자에게는 어려운 단어와 친절하게 "stdafx를 빠뜨렸습니까?" 라는 알림도 없었다. Precompiled header라는 개념을 모르는 초보자에게는 난감하기 그지 없는 메시지다. 물론 MSDN을 보면 자세히 나오지만.


두 번째:

Error C2628: 'CMyClass' followed by 'int' is illegal (did you forget a ';'?)

이 에러 메시지 역시 이제 친절하다. 그러나 C++ 처음 공부할 때는 이것 때문에 퍽이나 고생했다. 아시다시피 class 및 struct는 선언이 끝난 뒤 반드시 ;으로 마감을 해야 한다. 대표적인 예가 아래와 같은데:

// C2628.cpp
class CMyClass
{
void func(void)
{
}
} // missing semicolon

int main() // C2628
{
}

즉, class 선언 뒤에 ;가 빠져서 CMyClass뒤에 int가 바로 나와서 불법이라고 말해주고, 이제는 친절하게도 ;를 빠뜨렸는지 말해주고 있다. 왜 class 선언 뒤에 ;이 반드시 뒤 따라야 하나면 다음과 같은 문법이 가능하기 때문이다:

typedef class tagFoo
{
} foo;
사실 class 보다는 struct 선언을 위와 같이 하는 경우가 많다. 선언이 끝나고 바로 typedef를 할 identifier를 쓸 수 있기 때문에 ;은 중요한 의미를 가진다. 기억이 맞다면 Visual C++ 6.0에서는 이런 경우 에러 메세지가 이렇게 직관적이지 않고 꽤 어려운 형태였다. 한참 삽질하고 나서야 class 선언 뒤에 ;를 빼먹은 것을 발견할 수 있었다. 간단히 Cygwin에 깔린 gcc로 테스트 해보니

a.cc:9: error: new types may not be defined in a return type
a.cc:9: error: extraneous `int' ignored

와 같이 나왔다. VC6에서도 이와 비슷한 유형이었다.


세 번째:

error C2440: 'initializing' : cannot convert from 'Car *' to 'Object *'
Types pointed to are unrelated;
conversion requires reinterpret_cast, C-style cast or function-style cast

어려운 메시지는 결코 아니다. 그러나 C/C++의 참 난해하고 번거로운 #include 문제 때문에 발생한 문제였다. Object라는 base class가 있고 이를 상속받은 Car라는 클래스가 있다고 가정하자. 그리고 아래와 같이 Car*를 반환하는 함수를 호출한다: (편의상 소스 파일을 test.cpp로 하자.)

// Car* GetCarInstance();
Object* p = GetCarInstance();

전혀 문제 없는 코드이다. 그러나 C2400 에러 메시지를 얻었다. 실제로 내가 이것 때문에 좀 삽질을 하였는데, 그 이유는 저 구문이 컴파일 될 때, 클래스 Object와 Car가 단순히 declaration만 되어있었기 때문이다. 그래서 저 두 클래스 사이의 상속 관계를 전혀 몰랐기 때문이다. 그러니까 test.cpp 상단에

#include "car.h"

이런 것이 있어 클래스 Car에 대한 definition이 있었으면 괜찮았는데 (즉, class Car : public Object), 단순히

class Object;
    class Car;

와 같은 forward declaration만 있었기 때문이다.

왜 이런 경우가 일어났냐면, #include를 최소한으로 사용하려고 했기 때문이다. 특정 클래스에 대한 정의가 필요한 경우에만 (예: 멤버 변수 참조) #include하고 단순히 포인터 타입으로도 충분히 컴파일 할 수 있는 경우에는 바로 위와 같이 단순히 클래스 이름을 forward declaration만 해놓는 것이 좋다. 그래야 한 클래스의 헤더 파일을 바꿨을 때 재컴파일 되는 양을 최소화할 수 있다 (이것도 loosely coupled 철학의 실천?!). 또, 순환 참조 같은 것을 할 때는 forward declaration을 해야만 한다. 그러나 이런 노력의 부작용으로 C2440과 같은 경우도 일어날 수 있음을 알아두면 좋겠다.


그 외에도 초보 VC++의 가슴을 철렁이게 하는 LNK 2001, LNK 2005 에 대해서도, 그리고 아주 악명 높은 STL 에러 메시지에 대해서도 쓰고 싶으나 피곤한 관계로 여기까지만…

error LNK2001: unresolved external symbol "int i" (?i@@3HA)
error C2679: binary '=' : no operator found which takes a right-hand operand of type
'std::list<_Ty>::_Iterator<_Secure_validation>' (or there is no acceptable conversion)
1> with
1> [
1> _Ty=int,
1> _Secure_validation=true
1> ]
1> c:\program files\microsoft visual studio 8\vc\include\list(421): could be
'std::list<_Ty>::_Iterator<_Secure_validation> &std::list<_Ty>::_Iterator<_Secure_validation>
::operator =(const std::list<_Ty>::_Iterator<_Secure_validation> &)'
1> with
1> [
1> _Ty=float,
1> _Secure_validation=true
1> ]
1> while trying to match the argument list
'(std::list<_Ty>::_Iterator<_Secure_validation>, std::list<_Ty>::_Iterator<_Secure_validation>)'
1> with
1> [
1> _Ty=float,
1> _Secure_validation=true
1> ]
1> and
1> [
1> _Ty=int,
1> _Secure_validation=true
1> ]

컴파일러 버전이 높아지면서 단순히 ISO 표준에 맞추고 최적화 성능을 높이는 것뿐만 아니라 사용자에게 친절한 에러 메시지를 만드는 것도 주요한 임무일 것이다. 혹시나 VC++을 쓰면서 컴파일 에러 메세지가 난해하면 일단 MSDN부터 찾아보는 것이 좋다. 생각보다 가능한 모든 경우를 다 설명하고 있어서 참 친절하다.

by object | 2007/07/15 16:26 | 컴퓨터 | 트랙백 | 핑백(5) | 덧글(5)
트랙백 주소 : http://minjang.egloos.com/tb/1338651
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Linked at art.oriented : V.. at 2008/03/06 04:55

... 2005 이상을 써야할 이유가 충분하다. MS compiler extension이긴 하지만 편리한 키워드도 추가가 되었으며, profile-guided 최적화도 가능하고, 컴파일러 메세지도 보다 친절해졌으며, OpenMP도 그냥 지원이 된다. C99 기능들은 지원하지는 않지만 훨씬 C++ 표준에 부합된 프론트엔드를 가지고 있다. 7. 더 괜찮아진 IDE ... more

Linked at Death : Rebirth .. at 2008/03/06 09:41

... 2005 이상을 써야할 이유가 충분하다. MS compiler extension이긴 하지만 편리한 키워드도 추가가 되었으며, profile-guided 최적화도 가능하고, 컴파일러 메세지도 보다 친절해졌으며, OpenMP도 그냥 지원이 된다. C99 기능들은 지원하지는 않지만 훨씬 C++ 표준에 부합된 프론트엔드를 가지고 있다. 7. 더 괜찮아진 IDE ... more

Linked at jelly's 노트생각 : V.. at 2008/07/24 13:44

... 2005 이상을 써야할 이유가 충분하다. MS compiler extension이긴 하지만 편리한 키워드도 추가가 되었으며, profile-guided 최적화도 가능하고, 컴파일러 메세지도 보다 친절해졌으며, OpenMP도 그냥 지원이 된다. C99 기능들은 지원하지는 않지만 훨씬 C++ 표준에 부합된 프론트엔드를 가지고 있다. 7. 더 괜찮아진 IDE ... more

Linked at art.oriented : 링.. at 2009/01/06 07:48

... 했냐? 대충 이 정도만 되어도 훨씬 쉬울 것이다. VC++나 기타 에디터의 도움이 있다면 바로 링크 에러를 만든 소스 파일 위치로 점프할 수 있다. 컴파일러 에러는 점점 친절하게 진화하고 있다. 그러나 링크 에러 메세지는 어렵다. 초보자 뿐만 아니라 경험 많은 C/C++ 프로그래머도 링크 에러가 나오면 쉽지 않다. 그래도 링크 에러는 어렵다 혼자 만 ... more

Linked at Dreaming Of Plat.. at 2009/08/18 15:26

... 컴파일러 메세지도 보다 친절</a><a title="다음 링크를 새 창으로 엽니다. : '컴파일러 메세지도 보다 친절'" style="PADDING-LEFT: 15px; BACKGROUND: url(/plugins/NewWindowLink/newwindow.gif) no-repeat 0px 50%; BORDER-TOP-STYLE: none; MARGIN-RIGHT: -0.5em; BORDER-RIGHT-STYLE: none; BORDER-LEFT-STY ... more

Commented by Sikuru at 2007/07/15 17:44
Visual Studio 2005 부터는 참 컴파일러님이 마음씨가 좋아지셔서 저같은 초보에겐 매우 감지덕지랄까요 =)
Commented by 가이우스 at 2007/07/15 18:46
날이 갈수록 컴파일에러보다는 디버그질이 더 많아지더군요.
그게 더 무섭기도 하고요 ^^:;
Commented by object at 2007/07/16 00:51
이것 말고도 if (a == 10); 이렇게 쓰면 또 친절하게 warning을 띄어줍니다. 그리고 컴파일에러는 디버깅에 비하면 아무것도 아니죠. template 관련한 컴파일 에러가 아닌 이상에야 컴파일러 에러는 빙산의 일각이죠.
Commented by WakanaFan at 2007/07/16 15:57
2005씨는 상당히 친절하군요. 평소에 쓸일이 없는데다가 상당히 무거운 물건이라 안써서 몰랐는데...
학교 C 프로그래밍 시간에는 VS 6.0을 쓰고 있어서 덕분에 일부 학생들이 에러를 보고 다니던 기억이...
(확실히 에러코드와 MSDN을 애용하는 습관(?) 을 길러야..;;)
Commented by Ego君 at 2007/07/19 02:20
저도 2005는 정말 친절한것 같다는 것을 느껴요. 평소엔 6.0써서 그런지 2005같이 무거운 프로그램은 솔직히 쓰기가 그렇군요 :D

:         :

:

비공개 덧글

<< 이전 페이지 다음 페이지 >>





by 김민장 2008 이글루스 TOP 100
최근 등록된 덧글
개발자 입장에서의 수많은 ..
by Jiyoon at 02/04
저도 아들 돌잔치때 돌잡이 ..
by 박상욱 at 01/18
미국 대학원 원서 작성중에 p..
by 태클사이야 at 01/13
TO: 박PD 로그인 하지 않아..
by 박응용 at 01/10
http://gigglehd.com/zbx..
by dhunter at 12/28
우와.. 좋네요. 태반이 ..
by 윤광배 at 12/17
항상 좋은 글 잘 보고 있습니..
by y2k at 11/23
글이 좋아서 제 블로그에 담..
by 쏭섭 at 11/23
최근 등록된 트랙백
조엘 스폴스키의 강연 (Sta..
by 인덕원칸타타
[Redis] sds.c를 분..
by 조급하지말고 천천히
메뉴릿
이글루 파인더

website counter

Add to Google

rss

skin by 이글루스