Source : http://tomeii.com/bbs/board.php?bo_table=tipntech&wr_id=108&page=6


저도 디버깅쪽은 잘 못하지만 그래도 경험에 비추어(...) 얘길한다면, 우선 디버깅에 대해 나온 사이트는 잘 모르겠습니다. 사용법이라고 해봤자, 거기서 거기거든요. Visual Studio의 기본 기능만으로도 거의 대부분의 오류를 디버깅 할 수 있습니다.
우선, 디버깅 할때 제일 많이 뜨는 오류가 Access Violation 인데요, 잘못된 메모리 참조 오류입니다. 사실 다른데에서 오류가 나는 일은 극히 드물며, 포인터를 잘못 썼을경우에 나타나지요.
이런 경우 사용자가 프로그램을 쓰다가 프로그램이 죽는 일이 발생할 수 있으므로, 안정성에 문제가 생기며, 더욱 문제가 되는것은 이런 오류는 일정한 패턴이 없다는겁니다.
패턴이 없을땐 디버깅 하는게 속수무책이지만, 어느정도 패턴을 발견 했다면 디버깅이 훨씬 더 수월해집니다.

보통 제가 사용하는 디버깅 방법은, 프로그램을 디버그 모드로 실행시킨 뒤 메모리 참조 오류 메시지가 나올때까지 돌립니다. 돌리다보면 Visual Studio 6.0같은 경우에는, "Unhandled exception in ~~~.exe: 0xC0000005: Access Violation"와 같이 나오지요.
이런 메시지가 나오는 이유는, 도스시절이라면 가능했을, 이상한 메모리 영역(?)에 데이터를 쓰는것을 운영체제 차원에서 막기 때문에 일어나는 현상입니다. 잘못된 메모리 영역에 데이터를 무작위로 쓸 수 있다면, 운영체제의 안정성에 매우 큰 헛점이 발견될지도 모르는일이지요. 도스시절때는, 프로세스간의 메모리가 분리되어 있지도 않고, 운영체제가 이런 작업을 해주지 않아서 잘못 작업하면 프로그램이 잘 죽지요. 이럴때 프로그램만 죽는게 아니라 도스가 아예 맛이가지요.

오류 메시지가 나온 상태에서 확인을 누르면, 위치가 나옵니다. 하지만! 여기서 자신이 작성한 코드가 아닌게 나온다면, 다른 부분이 잘못된것이겠지요?
보통 MFC에서 많이 발생되는 현상인데요, MFC자체에도 버그가 있긴 하지만 메모리 누수정도의 버그정도기 때문에 프로그램이 뻗거나 그런 버그는 없습니다.(제가 알기론..)
이런 현상을 알기쉽게 설명한다면,

어떤 사람이 서울에서 총을 맞고
=> 우리가 제작한 코드안에서 잘못된 값을 입력해줘서..
아픈 몸을 질질 끌고 부산까지 내려가서
=> MFC 내부 함수로 데이터를 들고 들어가는거지요. MFC함수의 끝(?) 이전의 함수들은 어차피 함수의 함수를 호출하는것이기 때문에..
부산에서 죽은 경우이지요
=> 잘못된 데이터를 넣어줘서 MFC내부에서 죽은것이지요.

이런 경우에는, MFC내부의 버그로 보일수도 있으나, 99.99999% 잘못된 데이터의 입력으로 인해 생기는 경우입니다.
이런 버그는 잡기가 생각보다 쉬운데요, Visual Studio 6.0을 기준으로 설명하자면 실행중 특정 부분에 브레이크포인트를 잡거나 프로그램이 에러나고 멈춰선 부분에서 alt+6을 누르면 Call Stack가 나옵니다.
이게 무엇이냐 하면, 어떤 함수에서 어떤 함수를 호출했냐... 라는건데요, 이걸 보고 자신이 입력했던 코드까지 올라가보면 됩니다.
그러면 자신이 입력했던 코드의 어느 부분에서 오류가 나는지 알 수 있으며, 여기서 디버깅 하면 되겠지요.

아참, 보통 MFC에서 일어나는 오류라면 Assertion Failed오류가 납니다.
이건 무슨 오류냐...
MFC내부에서는 API함수를 호출하게 됩니다.
하지만 이 API함수를 호출하기 전에 현재 입력된 데이터가 유효한지 ASSERT로 점검을 해봅니다.
ASSERT란건 단순한 매크로 구문인데요, (따라가다 보면 이상한 함수들이..) 디버그 모드에서만 에러메시지를 출력해줍니다. 예를들어 아래와 같이 입력한다면,

ASSERT(a == 10);

?디버그 모드에서는 a가 10이 아닐 경우에 메시지를 출력합니다.
하지만 릴리즈 모드일때는 ASSERT구문은 생략됩니다.
(이런게 가능한 이유는 #ifdef~#endif에 의해서... 궁금하시다면 질문을~)
어쨌든, 예를들면,

CWnd a;
a.SetWindowPos(NULL, 0, 0, 0, 0, 0);

?와 같이 입력한 경우, a라는 변수는 윈도우 클래스인데요.. 핸들이 초기화 되지 않았으므로, SetWindowPos를 할 수 없습니다. 어차피 API함수중 SetWindowPos()가 잘못된 핸들에 대한 처리르 해주므로 에러처리를 해주던 안해주던 상관은 없지만 프로그래머가 실수를 할수도 있기 때문에 ASSERT를 해주는겁니다. 위와 같이 코딩하고 실행해보면 Assertion failed오류가 나는것을 확인할 수 있습니다. 내부적으로 핸들이 초기값인 NULL을 가지고 있어서겠지요..
이것도 MFC안에서 오류가 나기 때문에, 실제 자신이 코딩한 부분까지 콜스택을 이용해야 합니다.
콜스택을 이용하다가 보면, 위의 a.Set~~~ 줄에서 노란줄이 가져있는것을 볼 수 있습니다.

API같은 경우엔, 에러날일이 없지요.. API가 에러나면 대략 낭패이기 때문에 -ㅁ-;;

정리가 잘 안되서 읽기 힘드셨겠지만..;;
결국 디버깅은 삽질 * 삽질 입니다 -ㅁ-;;;

어쨌든 결론은.. 기본적인 툴인 콜스택만 알아도 디버깅이 수월하다는것! 그리고 위에서 설명은 안했지만, 아래의 Watch를 이용해도 쉽게 할 수 있구요. Watch의 사용방법은 왼쪽에 변수 이름만 써주면 되기때문에.. 매우 간단하지요. 

신고

Source : http://sjc333.egloos.com/2274953


vc6과 vs2005는 둘다 꾀나 명품들입니다.

윈도우에서는 98과 xp가 그러하듯 꾀나 사랑받고 있습니다.



요즘 만지작 거리는 프로그램은 vc6으로 되어 있었습니다.

보는 즉각, vs2005로 바꾸려고 했는데, 그놈에 차이점들 때문에 쉽게 안되더랍니다.


왠만한 차이점은 다 간파했는데, 오늘 만난것은 강적이였습니다.


조합형에서 보이는 코드가 완성형 문서 안에 적혀있었는데, 보통은 이런게 궭뒑 이런 식으로 보입니다.
그런데 오늘 문제를 일으킨 코드는 ? 닥치고 물음표로 보였던 것들. 
완성형에서는 '같' 인데 그걸 조합형 코드로 변환후, 
조합형코드 그대로를 완성형 문서에 적으면 ? 물음표로 보입니다.
이걸 vc6에서는 그냥 모르니까 물음표! 하지만 코드는 그 무언가 알 수 없는 그것을 유지해줍니다.

그러나 우리의 친절한 vs2005님께서는 그 무언가 알 수 없는 물음표? 를 진짜 물음표로 바꿔주십니다.
닥치고 코드는 완성형에서의 물음표 코드값으로 바꿔버리고, 유니코드 문서로 다시 바꿔주시는 친절함.
경고와 함께 절대로 완성형or조합형 문서로 저장할 수 없다고 빡빡 우깁니다. 데이터가 날아간다나 머라나.

덕분에 완성형<>조합형 변환 소스에 있는 매칭 코드 덩어리들이 전부 유니코드로 변환되어서
변환 프로그램을 새로 구해야 했습니다.

ㄱ-

새로 구한 프로그램은, 닥치고 유니코드에서도 그 형틀을 유지할 수 있도록
친히 핵사코드로 몽땅 하드코딩 되어 있답니다.


그런데 이 ㅅㅂㄻ 핵사코드 버젼님하는
모든 소스가 라이브러리 형식이 아닌, MFC에서 돌아가도록  프로그램 시작점(main함수)를 포함하고 있으며
stdafx따위와  표준을 과감히 무시하는 CString 님하까지 남발하여 리눅스에서도 돌아가게 해야하는
작업의 특성상 스트레스를 ;마ㅣ너레;ㅁ나ㅣ울;미ㅏㄴㅊㅍ;마ㅣㄴㅇㄹ;ㅡㅓ만ㄹ;

덕분에 새로 받은 조합형변환기도 대충 30%가량을 새로 작성했습니다.
필요함수만을 추출 분리하고, 표준에 맞추어 전부 바꾼후, 함수의 입출력 인자와 반환형을 기존의 변환함수들과
일치시키기........................쉽게 말해서 노!가!다!



감기 때문에 고생해 죽겠는데,
개막장코드를 상대하기 위해 소멸해버린 나의 아름다운 "코드 결벽증"을 에도하며
그 개막장코드를 vc6에서 vs2005로 바꾸기 위해서 캐고생을 하였습니다.




고생중에 가장 고생이였던 부분은,
vs2005가 지멋대로 유니코드로 문서를 저장시켜버려서 코드값이 뭉개졌다는 사실을 알아내기 까지였습니다.
조합형코드의 물음표가 유니코드고 머고간에 전부 그냥 닥치고 물음표로 보였기 때문에
버그의 원인을 알아내는데 대충 3시간은 걸린



아아아아아아아아악!!!!!!!!!!



버그 원인을 알아내게된 방법과 실마리는,
물음표가 2바이트 문자가 아닌 1바이트 문자여서 문자열의 바이트단위 길이가 달라졌다는것.




그 외에도 자잘하게
for(int i.......)
{
}

i=10;

따위의 문장에서 i값이 모르는넘이라고 생까주시는 vs2005님과,

내가 봐도 사실 생까도 괜찮은거 같은데 그걸 또 잘 돌려주시는 vc6 님 때문에 고생을 꾀나 했고

strcpy를 strcpy_s로 바꾸라고 우겨주시는 vs2005님과, (거기서 strcpy_s는 인자가 하나 더 많아 ㅠ_ㅠ)

#include <string> 이라고 .h를 무시하라는 vs2005

이어서 string은 std::string으로 적으라고 강요하지만, 꼬우면 using namespace std; 를 쓰면 되는데, 그런 팁 하나 없느
msdn ㅅㅂㄻ



여전히 왠만한 고급지식은 검색해도 안나와주는 한국의 웹.
결국 영어로 구글링




에효 그래도 자바보다는 쾌적한 개발환경같습니다.

자바와 톰켓과 mysql과, 콘솔에서의 한글 입력에서의 한글저장형식의 일치화란 ..... 킹오브 개막장. ㄱ-;;;;
그러고보니 자바도 유니코드로 넘어가고있는데 후덜덜

신고

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

D3DFORMAT  (0) 2010.11.02
[CPP] 디버깅에 관하여  (0) 2010.08.24
vc6과 vs2005의 차이로 오는 캐짜증남들  (0) 2010.08.24
VC++ 6.0을 쓰지 말아야하는 이유  (0) 2010.08.24
WINVER not defined. Defaulting to 0x0501  (0) 2010.08.24
Mac Adress(맥어드래스) 구하기  (0) 2010.08.24

Source : http://www.jjung.info/board/bbs/board.php?bo_table=Code_01&wr_id=41&sfl=&stx=&sst=wr_hit&sod=desc&sop=and&page=1


2008년 3월인 지금까지도 여전히 많은 프로젝트들이 10년 전에 출시된 VC++ 6.0으로 개발하고 있다는 사실이 다소 놀랍고 충격적이기까지 하다. 많은 분들이 토를 단다. 그런데 직접 십만 라인의 VC6 프로젝트를 2003년,VS 2003으로 이전한 경험이 있는 나로서는 그저 게을러서, 귀찮아서 라는 변명으로 밖에 들리지 않는다. 정말로 VC++ 6.0을 써야만 하는 절대절명의 이유가 있는지 정말 궁금하다. 왜 VC++ 6.0을 쓰지 말고 최소 VS 2005을 써야하는지 몇 가지만 써보자. (단, 이 이야기는 .NET을 사용하지 않는 Win32 기반의 C/C++ 프로젝트에만 적용된다.)

 

1. 보다 안전한 프로그래밍

2001년 온 세상을 골치아프게 했던 Code Red Worm을 기억할 것이다. 이건 대표적으로 heap buffer overflow의 결과인데, 이건 사소한 프로그래밍 실수 혹은 미비한 체크로 발생한다. 예를 들어, strcpy 같은 함수가 대표적이다. strcpy는 아시다시피 달랑 두 개의 스트링 인자만 받고 길이를 입력 받지 않는다. 그건 두 인자 모두 NULL로 안전하게 끝나는 것을 가정하기 때문이다. 그런데 의도적으로 할당된 버퍼보다 더 많은 문자열을 입력할 경우? 최악의 경우 재앙이 벌어질 수 있다. 실제 대부분의 버퍼 오버플로우는 이렇게 발생한다. VC++ 6.0에서는  strcpy를 써도 아무런 경고 따위 없다. 그러나 VS 2005 이상에서는 이런 함수는 쓰면 위험하다고 경고를 띄운다.

xxx.cpp(66) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

 

2. 유니코드 프로그래밍

아직까지도 유니코드가 아닌 MBCS로 시작하는 (윈도우) 프로그래머가 있으면 이건 기본도 모르는 사람이다. "아직 저희 제품이 윈도우 98을 지원 해야해서..." 라는 변명도 통하지 않는다. 그럴 경우에는 윈도우 95/98을 위한 Unicode Layer를 쓰면 된다. VS 2005에서 프로젝트를 하나 생성하면 디폴트가 유니코드이다. 이제 구닥다리 아스키 MBCS 기반의 프로그램을 짜야할 이유가 전혀 없다. 윈도우 NT 커널은 모두 유니코드로 짜여있어서 유니코드를 바로 쓰는 것이 성능에도 좋다. 예를 들어, CreateWindow라는 함수는 실제로 CreateWindowA라는 아스키 버전과 CreateWindowW라는 유니코드 버전이 있는데, 윈도우 NT 커널에서는 W 버전만 구현이 되어있다. 그리고 A 버전 함수가 불리면 입력 받은 스트링을 모두 유니코드로 바꾸는 과정을 거친 뒤, W를 실행시킨다. 참고로 윈도우 CE는 오직 유니코드만 지원한다. 따라서 아스키, MBCS를 써야할 이유가 이제는 없다. "윈도우 98 사용자들을 그래도..." 닥쳐라. 그냥 무시해라. 내 블로그 통계에 아예 Windows 98은 잡히지도 않는다.

영문 윈도우에서 non-Unicode 세팅을 영어로 했을 때, 여전히 ???와 같은 글씨가 보이는 프로그램들을 보면 한숨만 팍팍 나온다. 유니코드로 전환하는 것이 그렇게 어려운 것도 아니다. 사실, 제대로 공부 좀 했는 윈도우 프로그래머라면 10년 전 부터 이미 TCHAR, _T(x)와 같이 Unicode prepared된 코드를 만들었어야만 했다. 그러나 위에서도 말했듯이 이제는 모두 NT 기반 커널을 사용하기 때문에 TCHAR을 사용할 필요도 없다. 그냥 바로 wchar_t, L"Hello, World!"로 하면 된다.

반드시 알아야할 내용: http://eslife.tistory.com/entry/유니코드로-개발하기

 

3. 보다 뛰어난 인텔리센스

VC++ 2008은 아직도 안 써봐서 잘 모르겠지만, VC++ 2005의 인텔리센스만 해도 상당히 우수한 편이다. 물론 C#에서 지원되는 인텔리센스에 비하면 한참이나 모자라지만 기타 다른 모든 C/C++ 인텔리센스 중에서는 최고의 성능을 자랑한다고 확신한다 (이클립스, 소스인사이트 등등 모두 능가함). VC6 에서는 인텔리센스 기능이 초창기 버전이라 부족한 점이 매우 많았다. 대표적으로 #define으로 정의된 것들은 목록에 뜨지 않는다. 그리고 2003에 비해서도 성능이 많이 개선이 되었다. 여기에 적기에는 너무 장황해질 것 같아 생략하겠지만 2003에서는 처리가 안되어서 아쉬웠던 것이 2005에서 지원이 된 케이스가 있다. (이거 확인하고 바로 VS 2003 언인스톨)

VC++ 6.0 (사실 난 2002년부터 쓰지 않았다)을 쓸 때는 Visual Assist가 필수품이었는데 이제는 이걸 쓸 이유가 없다. Visual Studio가 지원하는 인텔리 센스만 해도 충분하기 때문이다.

 

4. STL의 (거의) 완벽한 지원

STL을 사용한다면 당장에 VC++ 6.0은 언인스톨 해야한다. 역시 eslife님이 아주 잘 정리를 해주셨기에 링크로 대체: http://eslife.tistory.com/entry/Visual-Studio-버전-별-STL-지원. 링크 글에도 나오지만 VS 2005의 STL 디버깅은 환상적이다. 예전에 STL 내용물 보기 위해 계속 노가다 뛰었던 걸 기억하면 눈물 날 정도다 (gdb에서는 dump 함수를 짜서 실행시키면 되긴 하지만 여전히 불편했다).

 

5. 뛰어난 IDE 매크로 사용

VC++ 6.0에서도 매크로가 되긴 된다. 그러나 Visual Studio .NET (7.0 버전)에서 부터 매크로가 매우 강력해졌다. IDE 하나가 DTE라는 객체로 접근이 되고 모든 IDE 객체 및 요소가 접근이 되고 매크로화 할 수 있다. 대표적으로 예를 하나 적어보면 .cpp와 .h를 연결해주는 매크로도 쉽게 만들 수 있다.

 

6. 더 훌륭해진 컴파일러

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

 

7. 더 괜찮아진 IDE

IDE만 놓고 보면 VC++ 6.0보다 많이 무겁다. 그러나 메모리 요즘 엄청나게 저렴하고 듀얼 코어 CPU도 저렴하니 그거 달면 가볍다. 회사에서 좋은 컴퓨터 안 사주면 회사 때려치던가 아니면 자기돈 들여서라도 좋은 컴퓨터로 바꿔야 한다. 남들 3분만에 컴파일할 것, 5분 동안 컴파일하면 그건 시간 낭비. 남은 2분 동안 최소 잠자거나 인터넷 서핑해도 남는 장사다. 그러니 최신 Visual Studio가 메모리 많이 먹는다는 것은 그다지 핑게거리가 되지 않는다.

VC++ 6.0의 IDE는 뭐랄까 애증이 교차한다. 희한하게도 이 IDE는 MFC로 만들어져 있어서 많은 호기심을 자아냈다. (단순하게 Spy++로 확인해보면 Afx:... 로 시작하는 Window Class Name이 확인 가능하다) 아마 마이크로소프트 내부에서 만든 프로그램 중 MFC를 쓴 것은 VC6과 Wordpad 정도가 아닐까? 그러나 VC++ 6.0의 IDE는 그다지 우수하지 않다. 일관성이 없다고 할 수 있다. 반면, Visual Studio .NET 부터는 모든 언어들이 공통적인 IDE로 통합이 되어 훨씬 일관성이 있는 UI로 바뀌었다. 물론 "ClassWizard가 사라졌어요!" 라는 비명이 잠시 들리지만 걱정 마시라, 다 있다. (물론 요즘 컴퓨터에서는 매우 가벼워진 VC6 덕택에 이 녀석을 에디터로 쓰시는 분들도 봤다)

VS 2003 시절까지만 해도 디버깅 심볼 서버 쓰기 위해서 삽질 좀 해야했던 것도 VS 2005에서는 그냥 된다. 또, VS 2003 까지만 해도 툴바 설정, 폰트 색깔 설정을 새 컴퓨터로 이동하기 위해 레지스트리도 백업해야하고 파일들도 카피해야했던 것에 비해, 세팅을 이전할 수 있는 기능을 built-in으로 지원한다. Team 버전은 사용하지 않았지만 거기에는 프로파일링, 유닛 테스트 등이 모두 포함되어있다고 한다. 마지막으로 VC6의 16색 썰렁한 아이콘에 비해 2005의 256색 아이콘은 더 이쁘다...

 

8. 멀티 코어의 사용

좀 와전된 내용이 있는 것 같은데, 최신 VC++ 컴파일러가 멀티 코어를 인식해서 뭔가 새로운 수준의 최적화나 컴파일을 하는 것은 아니다. 단순히 컴파일을 할 때, 멀티 코어를 다 활용하여 컴파일 시간을 단축시키는 것에 불과하다. 그래도 어쨌든 요즘 거의 기본인 듀얼 코어 환경에서 보다 빠르게 컴파일을 할 수 있다. VS 2005는 이 기능이 사실 미약해서 단순히 독립적인 두 프로젝트를 동시에 컴파일하는 수준이었는데, VS 2008은 모르겠다. 사실 컴파일은 그 자체가 embarrassingly parallel한 작업이라서 파일 수준으로 동시에 병렬적으로 컴파일을 할 수 있다.

 

9. MFC/ATL의 변화

VC++ 2008에는 제법 많은 MFC의 변화가 있다. 그러나 VS.NET부터도 변화가 적지 않게 있었다고 볼 수 있다. 바로 MFC와 ATL 중 공통적인 클래스들은 이들에 의존적이지 않고 사용할 수 있도록 된 것이다. 대표적으로 CString을 들 수 있다. VC++ 6에서는 CString 하나만 쓰려고 해도 MFC를 들고 다녀야만 했다. 그러나 버전 7, 그러니까 VS.NET 부터 (mfc70*.dll)는 CString, CRect, CPoint와 같은 타입들은 죄다 독립적으로 빠져 일반적인 Win32 프로젝트에도 붙여 쓸 수 있다.

 

또 뭐가 있을까. 정말 VC6을 아직도 쓰는 사람들이 있으면 도시락 싸가면서 말리고 싶다. 그 만큼 얻는 이득이 많다. 딱 하나 불편한 점이 있다면, MFC/ATL dll을 따로 배포해야 한다는 점 정도만 있을 것이다. 글쎄다. 정말 어떤 점이 VC6에서 VS 2005 혹은 VS 2008의 이전을 가로 막는지 궁금하다. VS 2008의 C/C++ 기능은 보다 많이 강화가 되었기 때문에 바꾸어야할 이유는 더 많아졌다.

운영체제야 비스타를 쓰라고 강요할 이유가 없다. 그러나 개발툴은 보다 안전하고 보다 빠르고 보다 효율적인 개발을 할 수 있다는 점에서 새 버전이 나오면 적극적으로 이전할 필요가 있다.

과거 십만 라인 프로젝트들을 바꿀 때, 쉽지는 않았다. 그런데 일주일 정도면 충분히 이전할 수 있었다. 오히려 컴파일러가 더 좋아지고 CString의 특정 함수의 프로토타입이 더 좋게 바뀌어서 잠재된 버그까지 잡을 수 있었다. 반복적인 노가다가 필요했지만 충분히 보상되고도 남는다. 그래서 더더욱 최소 VS 2005의 업그레이드를 추천한다.

신고

Source : http://iich.tistory.com/56


이전 버전의 VS(6.0)에서 작성한 프로젝트를 상위 버전 VS로 컴파일하면 

WINVER not defined. Defaulting to 0x0501 메시지가 출력된다.

StdAfx.h 파일 상당에 다음과 같이 정의해 주자.

#define WINVER 0x0501 (2003의 경우)
신고

Source : 데브피아

#include <IPHlpApi.h>                       // for GetAdaptersInfo()
#pragma comment( lib, "iphlpapi.lib" )
// MAC 가져오기
CString GetMACAddress()
{
    CString strMac;
 
    DWORD size = sizeof(PIP_ADAPTER_INFO);
    PIP_ADAPTER_INFO Info;
    ZeroMemory( &Info, size );
    int result = GetAdaptersInfo( Info, &size );        // 첫번째 랜카드 MAC address 가져오기
    if (result == ERROR_BUFFER_OVERFLOW)    // GetAdaptersInfo가 메모리가 부족하면 재 할당하고 재호출
    {
        Info = (PIP_ADAPTER_INFO)malloc(size);
        GetAdaptersInfo( Info, &size );
    }
    if (!Info) return strMac;
 
    strMac.Format( "%0.2X-%0.2X-%0.2X-%0.2X-%0.2X-%0.2X", Info->Address[0], Info->Address[1], Info->Address[2], Info->Address[3], Info->Address[4], Info->Address[5] );
    
    return strMac;
}
신고

Source : http://msdn.microsoft.com/ko-kr/library/da60x087.aspx

 

오류 메시지
'function' : 오버로드된 함수에 대한 호출이 모호합니다.

지정한 오버로드된 함수 호출을 해결하지 못했습니다.하나 이상의 실제 매개 변수를 명시적으로 캐스팅해야 할 수도 있습니다.

템플릿 사용을 통해 이 오류가 발생할 수도 있습니다.동일 클래스에서 정규 멤버 함수와 템플릿 기반 멤버 함수가 동일한 시그니처를 가지는 경우 템플릿 기반 함수가 먼저 와야 합니다.이는 Visual C++의 현재 구현에 대한 제한 사항입니다.

함수 템플릿의 부분 순서 지정에 대한 자세한 내용은 기술 자료 문서 Q240869를 참조하십시오.

ISupportErrorInfo를 지원하는 COM 개체를 포함하는 ATL 프로젝트를 빌드하는 경우에는 기술 자료 문서 Q243298을 참조하십시오.

예제


다음 샘플에서는 C2668 경고가 발생하는 경우를 보여 줍니다.

복사

// C2668.cpp
struct A {};
struct B : A {};
struct X {};
struct D : B, X {};

void func( X, X ){}
void func( A, B ){}
D d;
int main() {
   func( d, d );   // C2668 D has an A, B, and X 
   func( (X)d, (X)d );   // OK, uses func( X, X )
}

다음과 같이 using 선언을 사용하여 이 오류를 해결할 수도 있습니다.

복사

// C2668b.cpp
// compile with: /EHsc /c
// C2668 expected
#include <iostream>
class TypeA {
public:
   TypeA(int value) {}
};

class TypeB {
   TypeB(int intValue);
   TypeB(double dbValue);
};

class TestCase {
public:
   void AssertEqual(long expected, long actual, std::string
                    conditionExpression = "");
};

class AppTestCase : public TestCase {
public:
   // Uncomment the following line to resolve.// using TestCase::AssertEqual;
   void AssertEqual(const TypeA expected, const TypeA actual,
                    std::string conditionExpression = "");
   void AssertEqual(const TypeB expected, const TypeB actual,
                    std::string conditionExpression = "");
};

class MyTestCase : public AppTestCase {
   void TestSomething() {
      int actual = 0;
      AssertEqual(0, actual, "Value");
   }
};

Visual Studio .NET 2003에서는 컴파일러 규칙에 따라 이제 상수 0의 캐스팅에 대한 변환에 모호성이 있기 때문에 이 오류가 발생할 수도 있습니다.

상수 0을 사용한 캐스팅에 대한 변환의 경우 int를 long과 void* 모두로 변환해야 하기 때문에 모호성이 발생합니다.이 오류를 해결하려면 사용할 함수 매개 변수의 정확한 형식으로 0을 캐스팅하여 변환이 일어날 필요가 없게 만드십시오. 이렇게 하면 Visual Studio .NET 2003과 Visual Studio .NET 버전의 Visual C++ 모두에서 올바른 코드가 됩니다.

복사

// C2668c.cpp
#include "stdio.h"
void f(long) {
   printf_s("in f(long)\n");
}
void f(void*) {
   printf_s("in f(void*)\n");
}
int main() {
   f((int)0);   // C2668

   // OK
   f((long)0);
   f((void*)0);
}

이제 CRT가 모든 산술 함수에 float 및 double 형식을 사용하기 때문에 이 오류가 발생할 수도 있습니다.

복사

// C2668d.cpp
#include <math.h>
int main() {
   int i = 0;
   float f;
   f = cos(i);   // C2668
   f = cos((float)i);   // OK
}

CRT의 math.h에서 pow(int, int)를 제거한 경우에 이 오류가 발생할 수 있습니다.

복사

// C2668e.cpp
#include <math.h>
int main() {
   pow(9,9);   // C2668
   pow((double)9,9);   // OK
}
신고

출처 : http://blogs.msdn.com/b/kocssdva/archive/2007/11/27/vc-2005-lnk2019.aspx


Breaking Changes in the Visual C++ 2005 Compiler (C++)( http://msdn2.microsoft.com/ko-kr/library/ms177253(VS.80).aspx )  VC++ 2005 이전 version과는 다른 behavior 를 갖는 항목에 대해서 언급이 되어있는 데간혹이러한 차이 때문에 VC++ 2003에서는 정상적으로 Compile 이 되던 ProjectVC++ 2005에서는 Link Error가 발생하는 등의 현상을 겪을 수 있습니다예를 들어다음과 같은 LNK2019오류를 경험할 수 있습니다.

 

LNK2019 오류는 일반적으로 프로젝트가 참조하는 외부 DLL 파일에 사용하는 function이 정의되어 있지 않거나 혹은 Export되지 않았기 때문에 발생합니다

 

오류발생시에 메시지를 확인해보면 다음과 같은 외부함수를 참조하고자 시도 합니다아래 내용은 C++ Naming Mangling 규칙에 의해 encoding되며함수 이름 이하의 기호 및 문자들은 해당 함수의 return type parameter type을 근간으로 결정됩니다.

 

?osTHcreate@@YAIPBDHP6GIPAX@Z1PB_W_N@Z ? (1)

 

그러나 실제로 참조 되고 있는 DLL 파일에서 export 하고 있는 함수는 다음과 같은 signature를 가지고 있습니다.

 

?osTHcreate@@YAIPBDHP6GIPAX@Z1PBG_N@Z ? (2)

 

이러한 불일치로 인해 LNK2019 오류가 발생하고 있습니다. (1)  PB_W  wchar_t * 를 의미하며 (2) PBG unsigned short *를 의미합니다이 둘은 동일하게 2 byte의 메모리 공간을 필요로 하는 자료형이나, Visual Studio 2005 wchar_t *  unsigned short * 를 명시적으로 구분하기 때문에 Link 오류가 발생합니다. wchar_t  unsigned short 를 명시적으로 구분하는 것을 방지하기 위해서는 다음과 같이 Project의 속성을 wchar_t  C/C++의 내부자료형으로 사용하지 않도록 구성하면 됩니다.

 

To set this compiler option in the Visual Studio development environment

  1. Open the project's Property Pages dialog box. For details, seeModifying Project Settings.

  2. Click the C/C++ folder.

  3. Click the Language property page.

  4. Modify the Treat wchar_t as Built-in Type property.

신고

Source : http://creative.egloos.com/1610065

 

 

호스트에 2개 이상의 랜카드가 설치되어 있거나 하나의 랜카드이어도 여러 개의 IP 를 가지고 있는 경우, 인터넷에 연결된 IP 주소를 찾기는 방법으로 제가 추천하는 방법은 2가지가 있어요.

첫번째, 가장 쉬운 방법으로 아주 유명한 웹사이트에 TCP 연결을 한 후, 연결된 TCP 소켓에서 자신의 IP 주소를 가져오는 것입니다. 일부 FTP 클라이언트 프로그램에서 데이타 소켓의 주소를 처리할 때에 애용되는 방법이죠.

두번째, 오늘 생각해 낸 방법으로 호스트의 랜카드 및 IP 주소 리스트를 검색하여서 인터넷에 연결된 IP 주소를 찾는 방법입니다. 동작 원리를 간단히 설명하면 아래와 같아요.

(1) 호스트에서 사용하는 모든 랜카드를 검색하여 Default GW 주소가 설정된 랜카드를 찾는다.
(2) Default GW 주소가 설정된 랜카드의 모든 IP 주소를 검색하여 Default GW 의 Network 주소와 동일한 IP 주소를 찾는다.
(3) 위에서 찾은 IP 주소를 로컬 IP 주소로 리턴한다.

두번째 방법에 대한 소스코드는 아래와 같아요.

================================= 소스코드 =====================================

#include "stdafx.h" 
#include <winsock.h>

#include <ntddndis.h>

#include "iptypes.h" 
#include "ipifcons.h"

typedef DWORD (WINAPI *ADDIPADDRESS)( IPAddr, IPMask, DWORD, PULONG, PULONG ); 
typedef DWORD (WINAPI *DELETEIPADDRESS)( ULONG ); 
typedef DWORD (WINAPI *GETADAPTERSINFO)( PIP_ADAPTER_INFO, PULONG );

ADDIPADDRESS AddIPAddress = NULL; 
DELETEIPADDRESS DeleteIPAddress = NULL; 
GETADAPTERSINFO GetAdaptersInfo = NULL;

/** 호스트에서 인터넷에 연결되어 있는 IP 주소를 가져온다. */

if( hDll == NULL ) 

  hDll = LoadLibrary( "iphlpapi.dll" ); 
}

void PrintIP2() 

  // 호스트에 연결된 IP 주소 중에서 default gw 와 동일한 네트워크에 존재하는 IP 주소를 찾아낸다. 
  static HINSTANCE hDll;   // ICMP library handle

  if( hDll ) 
  { 
    DWORD dwErr, dwAdapterInfoSize = 0; 
    PIP_ADAPTER_INFO pAdapterInfo, pAdapt; 
    PIP_ADDR_STRING  pAddrStr;

    if( AddIPAddress == NULL ) 
    { 
      AddIPAddress = (ADDIPADDRESS) GetProcAddress( hDll, "AddIPAddress" ); 
      if( AddIPAddress == NULL ) goto NORMAL_CASE; 
    }

    if( DeleteIPAddress == NULL ) 
    { 
      DeleteIPAddress = (DELETEIPADDRESS) GetProcAddress( hDll, "DeleteIPAddress" ); 
      if( DeleteIPAddress == NULL ) goto NORMAL_CASE; 
    }

    if( GetAdaptersInfo == NULL ) 
    { 
      GetAdaptersInfo = (GETADAPTERSINFO) GetProcAddress( hDll, "GetAdaptersInfo" ); 
      if( GetAdaptersInfo == NULL ) goto NORMAL_CASE; 
    }

    if( ( dwErr = GetAdaptersInfo( NULL, &dwAdapterInfoSize ) ) != 0 ) 
    { 
      if( dwErr != ERROR_BUFFER_OVERFLOW ) 
      { 
        goto NORMAL_CASE; 
      } 
      // QQQ: ERROR_BUFFER_OVERFLOW 인 경우에는 어떻게 처리하지?? 
    }

    // Allocate memory from sizing information 
    if( ( pAdapterInfo = (PIP_ADAPTER_INFO) GlobalAlloc( GPTR, dwAdapterInfoSize )) == NULL ) 
    { 
      goto NORMAL_CASE; 
    }

    // Get actual adapter information 
    if( ( dwErr = GetAdaptersInfo( pAdapterInfo, &dwAdapterInfoSize ) ) != 0 ) 
    { 
      goto NORMAL_CASE; 
    }

    for( pAdapt = pAdapterInfo; pAdapt; pAdapt = pAdapt->Next ) 
    { 
      switch ( pAdapt->Type ) 
      { 
        case MIB_IF_TYPE_ETHERNET: 
          // QQQ: 여러개의 default GW 가 나올 수 있으나, 현재는 첫번째 default GW 만 생각한다. 
          if( strlen( pAdapt->GatewayList.IpAddress.String ) > 0 ) 
          { 
            DWORD dwGwIp, dwMask, dwIp, dwGwNetwork, dwNetwork;

            dwGwIp = inet_addr( pAdapt->GatewayList.IpAddress.String );

            //printf( "Gateway address = [%s] ", pAdapt->GatewayList.IpAddress.String ); 
            //printf( "Gateway mask = [%s] ", pAdapt->GatewayList.IpMask.String );

            for( pAddrStr = &(pAdapt->IpAddressList); pAddrStr; pAddrStr = pAddrStr->Next ) 
            { 
              if( strlen(pAddrStr->IpAddress.String) > 0 ) 
              { 
                dwIp = inet_addr( pAddrStr->IpAddress.String ); 
                dwMask = inet_addr( pAddrStr->IpMask.String ); 
                dwNetwork = dwIp & dwMask; 
                dwGwNetwork = dwGwIp & dwMask;

                //printf( "IP address = [%s], network = %08x ", pAddrStr->IpAddress.String, dwNetwork ); 
                if( dwGwNetwork == dwNetwork ) 
                { 
                  printf( "ip address = %s ", pAddrStr->IpAddress.String ); 
                  break; 
                } 
              } 
            } 
          } 
          break; 
        default: 
          break; 
      } 
    } 
  }

}

int _tmain(int argc, _TCHAR* argv[]) 

  PrintIP2();

  return 0; 
}
신고

출처 : http://towanouta.tistory.com/124

 

DirectX SDK를 설치하고 나서 빌드하기 위해서는 개발환경을 설정해 줄 필요가 있다.
보통 학생들이 아직도 많이 사용하고 있는 VC++ 6.0과 VC++ 2005(.NET)이 있는데 두가지의 설정법은 비슷하다.
보통은 Include폴더와 Lib폴더가 자동으로 추가되지만 추가되지 않았을 경우 확인하고 결로를 지정해 주어야 정상적으로 빌드가 가능하다.
그리고 추가적으로 d3d.lib , d3dx9.lib , winmm.lib 라이브러리 파일을 링크시켜주어야한다.
위의 파일들을 링크 시켜주지 않으면 빌드시 error LNK2019 의 링크 에러를 낼 수 있다.
[ VC++ 6.0에서 ]

§ 헤더파일과 라이브러리 파일 경로지정

도구 - 옵션 - 디렉토리 항목에서 다음과 같이 경로를 추가해주어야 한다.
라이브러리 파일 : C:\DXSDK\Lib
포함 파일 : C:\DXSDK\Include

§ 프로젝트에 라이브러리 파일 링크하기

프로젝트 - 설정 - 링크 탭에서 링크할 라이브러리 파일을 추가한다.
  d3d.lib d3dx9.lib winmm.lib

[ VC++ 2005(.NET)에서 ]

§ 헤더파일과 라이브러리 파일 경로지정

도구 - 옵션 - 프로젝트 및 솔루션 - VC++ 디렉터리 항목에서 각 항목을 선택하고 경로를 추가한다.
라이브러리 파일 : C:\DXSDK\Lib
포함 파일 : C:\DXSDK\Include

clip_image002

clip_image004

§ 프로젝트에 라이브러리 파일 링크하기

프로젝트 - 구성 속성 - 링커 - 입력 폴더의 추가종속성에 다음 파일들을 추가시켜준다.
  d3d9.lib d3dx9.lib winmm.lib

clip_image006

위와 같이 설정했다면 DirectX 예제 프로젝트를 빌드해보고 설정이 제대로 되었는지 확인합니다.
빌드가 되지 않는다면 지정해준 경로상에 라이브러리폴더와 포함폴더가 제대로 있는지 확인합니다.

신고

출처 : http://kwangho.tistory.com/985

 

환경사항
Windows XP Service pack 3 + Visual studio 6.0 + Platform SDK Server2003 R2 사용

에러 메시지
uuid.lib(ocidl_i.obj) : fatal error LNK1103: debugging information corrupt; recompile module

Error executing link.exe.
해결책

C:\Program Files\Microsoft Platform SDK\Lib 폴더의 uuid.lib 파일의 이름을 삭제 또는 변경해주면 됩니다.

신고

+ Recent posts