|
컴파일러 에러 메시지들 중에서 명백한 것도 많지만 난해한 것도 많았다. Visual Studio에 있는 C/C++ 컴파일러 메시지 중 난해한 것들 중 몇 가지들은 이제 꽤나 친절한 메시지로 바뀌었다. 몇 가지 대표적인 컴파일러 에러 메시지에 대해서 이야기 해보자.
Fatal error C1010: unexpected end of file while looking for precompiled header. 초보자들이 겪었던 대표적인 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까지는:
라고 떴었다. "directive"라는 다소 초보자에게는 어려운 단어와 친절하게 "stdafx를 빠뜨렸습니까?" 라는 알림도 없었다. Precompiled header라는 개념을 모르는 초보자에게는 난감하기 그지 없는 메시지다. 물론 MSDN을 보면 자세히 나오지만.
이 에러 메시지 역시 이제 친절하다. 그러나 C++ 처음 공부할 때는 이것 때문에 퍽이나 고생했다. 아시다시피 class 및 struct는 선언이 끝난 뒤 반드시 ;으로 마감을 해야 한다. 대표적인 예가 아래와 같은데: // C2628.cpp 즉, class 선언 뒤에 ;가 빠져서 CMyClass뒤에 int가 바로 나와서 불법이라고 말해주고, 이제는 친절하게도 ;를 빠뜨렸는지 말해주고 있다. 왜 class 선언 뒤에 ;이 반드시 뒤 따라야 하나면 다음과 같은 문법이 가능하기 때문이다: typedef class tagFoo사실 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 와 같이 나왔다. VC6에서도 이와 비슷한 유형이었다.
error C2440: 'initializing' : cannot convert from 'Car *' to 'Object *' 어려운 메시지는 결코 아니다. 그러나 C/C++의 참 난해하고 번거로운 #include 문제 때문에 발생한 문제였다. Object라는 base class가 있고 이를 상속받은 Car라는 클래스가 있다고 가정하자. 그리고 아래와 같이 Car*를 반환하는 함수를 호출한다: (편의상 소스 파일을 test.cpp로 하자.) // Car* GetCarInstance(); 전혀 문제 없는 코드이다. 그러나 C2400 에러 메시지를 얻었다. 실제로 내가 이것 때문에 좀 삽질을 하였는데, 그 이유는 저 구문이 컴파일 될 때, 클래스 Object와 Car가 단순히 declaration만 되어있었기 때문이다. 그래서 저 두 클래스 사이의 상속 관계를 전혀 몰랐기 때문이다. 그러니까 test.cpp 상단에 #include "car.h" 이런 것이 있어 클래스 Car에 대한 definition이 있었으면 괜찮았는데 (즉, class Car : public Object), 단순히 class Object; 와 같은 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 컴파일러 버전이 높아지면서 단순히 ISO 표준에 맞추고 최적화 성능을 높이는 것뿐만 아니라 사용자에게 친절한 에러 메시지를 만드는 것도 주요한 임무일 것이다. 혹시나 VC++을 쓰면서 컴파일 에러 메세지가 난해하면 일단 MSDN부터 찾아보는 것이 좋다. 생각보다 가능한 모든 경우를 다 설명하고 있어서 참 친절하다.
최근 등록된 덧글
개발자 입장에서의 수많은 ..
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 최근 등록된 트랙백
메뉴릿
이글루 파인더
|