yjh_common.source.utility.test_debugging 참고


CRT(C Runtime) Debugger사용방법


일반적으로 가장 잡기 힘든 버그의 하나로서 메모리 누수, 메모리 Overwrite등을 꼽을 수 있다. 이런 문제점을 해결하기 위해 CRT(C Runtime library)에서는 여러가지 다양한 메모리 관련 디버그 함수들을 제공한다. 그러나 이것들이 디폴트로 사용하기 힘들게 꺼져 있기 때문에 대부분의 프로그래머들은 이 사실을 알지 못하는 경우가 많다. 그래서 이 글에서는 CRT의 디버그 관련 함수들에 대해 알아보고 어떻게 사용하는 것이 좋은지에 대해 논해 보려고 한다.


John Robbins(필자가 가장 좋아하는 프로그래머 중의 한명)가 지은 Debugging Applications 이라는 책에도 좋은 내용들이 있으니 참고하기 바란다. 그러나 여기 나온 팁은 그 책에는 나와 있지 않은 것이다. Numega Bounds Checker나 Rational Purify등의 툴이 비싸서 엄두도 못내는 분들께는 좋은 내용이 되리라 믿는다


메모리 누수


개요


CRT가 출력해 주는 메모리 누수 리포트 결과를 간혹 본적이 있는 사람도 있을 것이다. 만약 MFC를 주로 사용한다면 이와 같은 메시지를 자주 볼 수 있다. 왜냐하면 MFC에서는 기본적으로 CRT 디버그 기능을 켜기 때문이다. 메시지 내용은 다음과 같다


Dumping objects ->

{65} normal block at 0x003748B0, 48 bytes long.

Data: <@H7 @H7 @H7 > 40 48 37 00 40 48 37 00 40 48 37 00 CD CD CD CD

{64} normal block at 0×00374840, 48 bytes long.

Data: < H7 H7 H7 > B0 48 37 00 B0 48 37 00 B0 48 37 00 CD CD CD CD

Object dump complete.


이 메시지의 내용은 두개의 블록이 할당된다음 해제되지 않았다는 것을 의미한다. 그렇다면 우선 이 메시지들에 대해 대략 알아보도록 하자


우선 {64}, {65}와 같은 것은 메모리에 할당된 순서로서, 각각 64번째, 65번째 할당된 메모리가 해제되지 않았음을 나타낸다. Normal block이라 함은 사용자에 의해 일반적인 new, delete, malloc등으로 할당된 메모리라는 뜻이다. 그리고 그 메모리 포인터 주소를 알려주고 있으며, 몇 바이트짜리 메모리 블록인지도 나와 있다


Data:… 라인은 그 메모리의 선두번지로부터 실제 메모리의 내용이 어떤 값을 포함하고 있는지를 나타내는 것이다


그러나 위의 메시지를 보았듯이 실제로는 아무 도움이 되지 않는다는 것을 금방 알수 있을것이다. 왜냐하면 메시지의 내용이 너무 암호와같이 복잡하다는데 문제가 있다. 몇줄짜리 프로그램이라면 또 모르겠으나, 거대한 프로그램인 경우 실제로 64,65번째 할당된 메모리를 순서대로 추적하는 것은 너무나도 어려우며, 어떤 포인터에 어느 번지의 메모리가 할당되었는지를 확인하는 것도 불가능에 가깝다고 할 수 있다. 또 자신이 만든 클래스나 구조체가 몇 바이트짜리인지를 일일이 확인한다는 것도 불가능하다.


그렇다면, 이 문제를 어떻게 해결해야 할 것인가? 실제로 CRT에는 여러가지 도우미 함수들을 포함하고 있어서 이 문제를 좀 더 쉽게 해결할 수 있도록 해 준다. 그러나 제대로 알고 사용하지 않는다면 결국에는 또다른 암호 코드만을 추가로 더 얻게 될 뿐이라는 것도 알아야 한다


샘플코드


#include “stdafx.h”

int main()

{

int *p = new int;

return 0;

}


위의 코드는 int *를 할당하고 해제하지 않았으므로 명백한 메모리 누수이다. 그러나 이 프로그램을 빌드하고 디버그해봐도 프로그램 종료시 아무런 메시지를 남기지 않는다. 즉 메모리가 샌것인지, 혹은 Overwrite가 일어났는지 등을 확인할 길이 전혀 없다. 그러면 프로그램 일부를 수정해 보도록 한다


#include “stdafx.h”

#include <crtdbg.h>

int main()

{

int *p = new int;

_CrtMemDumpAllObjectsSince(0);

return 0;

}


_CrtMemBumpAllObjectsSince를 사용하기 위해 crtdbg.h를 인클루드 하고, 프로그램 종료 직전에 함수를 호출했다 디버그를 시작하고 프로그램을 종료하면 출력결과는 다음과 같다


Dumping objects ->

{64} normal block at 0×00374838, 4 bytes long.

Data: < > CD CD CD CD

Object dump complete.

‘[2288] crtdbg.exe: 기본’ 프로그램이 0 (0×0) 코드에서 끝났습니다.


위에서 설명한것과 비슷한 종류의 메시지가 포함되어 있는 것을 알 수 있을 것이다. 이 메모리는 64번째 할당된 일반 메모리이며 0×00374838번지에 4바이트 할당되었음을 알 수 있다. 또 데이터 내용은 16진수로 CD CD CD CD이다 이 정보만으로도 많은 것을 알 수 있다. 예를들어 데이터가 CD CD CD CD라는 것은 할당만 해놓고 전혀 초기화를 하지 않았다는 의미이다. 단순한 위의 프로그램 만으로도 사용자가 처음 할당한 메모리가 64번째만에 할당되었다. 이유가 무엇일까? 이유는 간단하다. main함수가 호출되기 이전에 이미 많은 메모리 할당 요청이 있었고, 그것은 프로그램을 실행시키기 위해 운영체제나, CRT가 이미 사용했기 때문이다. 위의 프로그램은 단순하기 때문에 어디서 메모리가 샜는지 한눈에 척 알 수 있다. 그러나 메모리를 수십~수백번씩 할당했다 해제하는 일반 애플리케이션에서는 어떻게 정확히 64번째 할당된 메모리를 찾아낼 수 있을까? CRT에서 내준 정보는 CRT를 이용해 분석 가능하다 main함수가 처음 시작되기 전에 다음의 함수를 사용하도록 하자


_CrtSetBreakAlloc(64);

int *p = new int;


이 함수는 64번째 메모리 할당이 발생할 경우 프로그램 실행을 중지하고 디버거로 제어를 넘기라는 의미이다. 실제로 프로그램을 실행시켜 보면, “crtdbg.exe의 0x00411cb7에 처리되지 않은 예외가 있습니다. 사용자 중단점”과 같은 메시지를 출력하면서 프로그램 실행을 중지하게 된다. 브레이크 포인트가 가리키는 위치는 CRT의 메모리 할당 함수 내부이며, Call Stack을 따라가 보면 어느곳에서 할당이 일어났는지 바로 알수 있게된다.


전역 변수와 CRT 디버깅


다음과 같은 프로그램을 보도록 하자


#include “stdafx.h”

#include “crtdbg.h”

#include <crtdbg.h>

class A

{

public:

A() { p = new int; }

private:

int *p;

};

A a;

int APIENTRY _tWinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPTSTR lpCmdLine,

int nCmdShow)

{

_CrtSetBreakAlloc(64);

_CrtMemDumpAllObjectsSince(0);

return 0;

}


이 프로그램을 디버그 해 보면 똑 같은 메모리 누수를 보고하긴 하지만, 그러나 64번째 메모리 할당에서 정지하지 않는다. 이유가 무엇일까?


이유는 간단하다. A라는 클래스의 인스턴스인 a가 전역변수로 선언되었기 때문에 main함수가 호출되기 이전에 생성되기 때문이라는 것이다. a가 이미 생성되고 난 다음에 브레이크 포인트를 설정하니, 브레이크 포인트가 먹힐리가 없다. 그럼 방법이 없는 것일까?


답은 간단하다. 모든 할당이 일어나기 직전에 프로그램을 정지시켜놓고, 64번째 메모리 할당이 일어날 때 브레이크 하라는 명령을 주면 된다. 그럼 어떻게 하면 될까? 다음과 같이 하도록 한다.


1. CRT소스에서 WinMainCRTStartup()함수를 찾아낸다. 이 함수는 실질적인 main함수이며, 프로그램이 로드되기 전에 가장먼저 실행된다. 이 함수 내부에서 여러분이 정의한 main 또는 WinMain함수를 호출하게 된다. 이 함수는 파일의 찾기 기능을 이용하거나, 또는 crt0.c파일을 바로 열어서 찾아도 된다. 그러나 더 간단한 방법은 main함수에 BP를 찍어놓고, 한번 실행시킨다음 call stack을 거슬러 올라가는 방법이다.

2. WinMinCRTStartup함수의 시작부분에 BP를 찍어놓고 다시 디버거를 시작시킨다

3. Watch창을 열어 _crtBreakAlloc 변수를 확인해 본다. 아마 -1일 것이다.

4. 이 변수값을 원하는 메모리 할당 번지(위의 경우64)로 바꾼다.

5. 다시 실행시키면 64번째 메모리 할당을 하기 전에 정지한다.


이 기술은 코드를 재 컴파일 하지 않아도 디버거 상에서 바로 브레이크 포인트를 수정할 수 있다는 장점이 있다. 현재 이 방법 보다 간단하게 할 수 있는 방법은 현재 연구중에 있다. 좋은 결과가 나오는대로 다시 여러분들에게 알려드리도록 하겠다.


이상 몇가지 메모리 누수를 찾아내는 방법을 살펴보았다. 그러나 주의할 것은 반드시 crtdbg.h를 같이 인클루드 해야 한다는 것이며 _DEBUG매크로가 정의되어 있을때에만 제대로 동작한다는 것이다. 오늘은 이 정도로 글을 마무리할 생각이며 남은 몇 개의 팁들은 필자 시간나는대로(-_-) 정리해서 올릴 계획이다. 그러므로 너무 기다리지 않는 것이 정신 건강상 좋을 것이다. 참고로 필자는 매우 게으르다 -.-


요즘 CRT의 디버그 기능을 연구하기 시작하면서, 그동안 정말 좋은 기능들을 여럿 묵혀놓았다는 느낌을 지울수가 없습니다. 어렵게 메모리 관련 디버깅 루틴을 만들지 않아도, 너무나도 정확히 메모리 관련 에러를 잡아주니 STL을 처음 쓸 때 만큼이나 편리하게 느껴지더군요. 그럼 그동안 제가 연구한 것에 대해 보고드리도록 하겠습니다


지난 내용의 메모리 누수가 아닌 것 까지 모두 보고하는 문제


지난번 예제에서 약간만 더 수정해 보자


#include “stdafx.h”

#include <crtdbg.h>

#include <list>

using std::list;

typedef list<int> IntList;

typedef IntList::iterator IntListIter;

IntList myList;

int main()

{

_CrtMemDumpAllObjectsSince(0);

return 0;

}


위의 프로그램은 메모리 누수를 한 개 보고한다. 위치는 myList의 생성자이다. 그러나 정말 그것이 샌것일까? 그렇다면 STL은 항상 메모리 누수가 있다는 말인가.. 이것저것 고민하던 중에, 진짜 Main함수는 WinMainCRTStartup()라는 사실이 생각났고, 디버그 상에서 WinMainCRTStartup() 메소드의 끝까지 따라가 보았다. 그랬더니 다음과 같은 루틴을 찾을 수 있었다. (처음에는 숨겨진 함수를 찾았다고 생각했으나, 알고봤더니 MSDN에 이미 문서화 되어있는 함수였다. 역시 소스보다는 문서를 찾아보는 것이 우선이다 -.-)


/* Dump all memory leaks */

if (!fExit && _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)

{

fExit = 1;

_CrtDumpMemoryLeaks();

}


_CrtSetDbgFlag이라는 함수는 CRT디버거의 전역 플랙을 셋팅하는 함수이다. 위에서 보다 시피 이미 CRT의 메인함수가 종료할 때 메모리 누수를 검사하고 있었던 것이다. 다만 디폴트로 꺼져 있었으며 열쇠는 _CrtSetDbgFlag이라는 함수가 쥐고 있다. MSDN에서 찾아본 결과 다음과 같다.


_CrtSetDbgFlag함수는 다섯개의 Flag이 있다.

_CRTDBG_ALLOC_MEM_DF : 디폴트로 켜져 있으며, 디버그 버전에서 모든 메모리 할당이 일어날 때마다 추적 가능하도록 특별한 기능을 추가해 둔다. 이 플랙이 켜져 있어야 메모리 누수를 안전하게 검사 할 수 있다.

_CRTDBG_DELAY_FREE_MEM_DF : delete, free등으로 삭제되어도 바로 삭제되지 않고, CRT의 메모리 관리소에 남아 있다가 프로그램 종료시에 완전히 삭제된다.

_CRTDBG_CHECK_ALWAYS_DF : 모든 메모리관련 연산에서 _CrtCheckMemory를 호출한다. 이 메소드는 이후에 다시 살펴볼 것임

_CRTDBG_CHECK_CRT_DF : CRT가 내부적으로 할당한 블록도 메모리를 체크할 때 포함한다. 일반적으로는 CRT가 할당한 블록은 메모리 체크에서 제외된다. 일반적으로 사용하지 않는다

_CRTDBG_LEAK_CHECK_DF : 프로그램이 완전히 종료되기 직전에 아직 해제되지 않은 메모리가 있는지 검사한다. 프로그램의 종료 포인트가 여러군데 있는 경우에 사용하면 일일이 _CrtDumpMemoryLeaks 메소드를 호출하지 않아도 자동적으로 메모리 누수를 검사할 수 있게된다.


이 중에서 첫번째 플랙만을 제외하고는 모두 디폴트로 꺼져있다. 그러므로 다음과 같이 메모리 검사 기능을 켜도록 한다

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

위의 프로그램에서는 다음을 삭제한다 _CrtMemDumpAllObjectsSince(0);

_CrtMemDumpAllObjectsSince 함수는 실제로는 특정 지점에서 지점간에 할당되어 있는 메모리들을 보고해 주는 함수이다. 인자로 0을 넘겨주면 처음부터 지금까지 할당되어 있는 메모리들을 보고해 준다. CRT가 아직 전역으로 할당된 메모리를 완전히 삭제하기도 전에 호출했기 때문에 STL의 메모리가 샌 것 처럼 보인것이다.


20141120 연준희 추가

이렇게 해도 계속 샌 것 처럼 보이는 경우가 있다.

Solution:
The solution is to ignore what is (likely) a false report, or change the static std::string objects to static std::string* pointers. Then make a static initializer/destructor that news/deletes those string objects. This means the memory is allocated on the stack, and comes/goes in the scope of the program. The other thing you do is file a bug with Microsoft and put a few comments on the documentation website that indicates the statics are still leaking and they haven’t really fixed it yet. :)

Links:
Bug report I submitted with response here 
<https://connect.microsoft.com/VisualStudio/feedback/details/697181/crt-memory-leak-detection-routines-still-report-statically-allocated-stl-objects-as-leaks#tabs>

MS article about CRT memory debug operations that says this bug had been fixed.
http://msdn.microsoft.com/en-us/library/x98tx3cf.aspx

출처: http://mattfife.com/?p=481


CRT 메모리 블럭


다음으로 넘어가기 전에 다음을 짚어보고 넘어가기로 하자. 디버그 버전에서는 메모리가 할당되거나 사용되기 직전에 특정한 값들로 할당된 메모리가 채워진다는 것을 알고 계실것이다. 의미는 다음과 같다


0xFD : 메모리 블록 양 끝의 버퍼에 생성된다

0xCD : 새로 생성된 버퍼에 저장되는 기본값이다

0xCC : 스택에 변수가 생성되면 우선 이값으로 채워진다

0xDD : 삭제된 메모리 블록은 이 값으로 채워진다


다음 예제를 보자


int main()

{ // 함수 시작지점

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

int *p = new int [10]; // 메모리가 할당되는 지점

printf(“%d”, *p);

delete [] p; // 메모리가 삭제되는 지점

return 0;

}


함수 시작지점에서 포인터 p는 초기값으로 0xCCCCCCCC를 갖게 된다. 디스어셈블 해보면 모든 지역변수들을 0xCC로 채워넣는 것을 볼 수 있다. 이후 메모리가 할당되는 지점에서 아마도 sizeof(int) * 10 바이트의 메모리가 할당될것이다. Sizeof(int)가 4바이트라면(32비트 운영체제에서) 40바이트가 생성되는 것이다.(디버그 버전이라는 가정하에) 이렇게 생성된 40바이트에 0xCD값이 채워진다. 만약 어떤 포인터의 값을 읽었을 때 값이 0xCDCDCDCD와 같은 형식이거든 초기화안된 메모리를 읽었다고 생각하면 된다.


그런데, 위의 할당지점에서 실은 48바이트가 생성된다. 40바이트 할당 명령을 주었는데 왜 48바이트의 메모리가 할당되었는가 이유는 위의 0xFD값에 있다. 40바이트의 블록을 생성시키고 그 블록의 앞과 뒤에 각각 0xFDFDFDFD를 삽입시켰기 때문이다. 이 값이 채워지는 이유는 다음과 같이 접근하는 경우


p[-1] = 10; // underwrite

p[11] = 10; // overwrite


0xFD로 채워진 메모리의 일부분이 깨질 것이고, 나중에 사용할 메모리 체크 명령에 의해 overwrite/underwrite가 발생했다는 사실을 알 수 있게된다.


마지막으로 메모리가 삭제되는 지점에서는 이론 대로라면 p값이 0xDD로 채워질 것이다. 그러나 실제로 필자의 컴퓨터에서는 0xFEEE가 채워졌다. 왜 그런지는 좀더 연구해 보고 알려드리도록 하겠다. -.- 오늘은 일단 여기까지 접고 연구결과가 더 나오는대로 여러분께 보고하는 시간을 갖도록 하려한다.. 그럼 다들 즐푸하시길..


지난번에 이어 이번에는 메모리에 어떤 문제가 있었는지를 체크해주는 _CrtCheckMemory함수에 대해 연구해 보도록 하겠습니다.

지난 강좌에 대해

강좌를 진행하기 전에 지난번 강좌 마지막 부분에서 메모리가 삭제될 때 0xDD값 대신에 0xFEEE값이 채워지는 이유를 찾아본 결과 CRT에서는 0xDD값을 정확히 채워 넣는다는 것을 확인하였다. _CRTDBG_DELAY_FREE_MEM_DF 플랙이 디폴트로 꺼져 있기 때문에 삭제했다는 표시를 하고 난 다음 바로 운영체제에서 삭제(진짜 삭제) 해버렸기 때문이다. 이부분은 뒤에서 다시 알아보도록 하겠다.

_CrtCheckMemory()

지난번에 알아보기를 CRT에서 메모리를 할당하려 할 때 몇가지 정보블럭들을 설정한다는 것을 알았을것이다. 자 이제는 설정된 정보블럭들을 검사할 차례이다. 문제는 일일이 디버거의 Watch창이나 Memory창을 이용해 블록이나 스택이 깨졌는지를 확인해야 한다는 것이다. 이런 기법은 아마도 잘 알고 있을 것이다. 특정 메모리 주소를 가르키게 해놓고 의심되는 코드를 실행시켰을 때 Memory창의 내용이 빨간색으로 변하는 모양을 살펴서, 엉뚱한 부분까지 쓰거나, 원치않은 결과를 얻는지를 확인하는 것이다. 문제는 이것이 너무나도 수동적이기 때문에 CRT에서는 _CrtCheckMemory라는 도우미 함수를 곁들였다. 이 함수는 몇가지 경우에 있어서는 아주 쓸만하다. 사용법을 보자

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

{

if(_CrtCheckMemory() == 0)

return -1;

return 0;

}

그냥 메모리 체크를 하기 원하는 위치에 _CrtCheckMemory함수를 삽입하기만 하면된다. 만약 0을 리턴한다면 할당된 메모리에 어떤 문제가 발생했다는 것을 의미한다. 그러나 위의 코드는 문제가 하나 있는데 바로 모든 CRT의 디버그 함수들은 DEBUG버전에서만 의미를 가지기 때문에 RELEASE버전에서는 아무 의미없는 코드가 된다는 것이다. 일단 보기에도 두 줄에 걸쳐 표기되어 있으므로 흉하다. 그러므로 다음과 같이 코딩하도록 한다.

_ASSERTE( _CrtCheckMemory( ) );

_ASSERTE는 CRT에서 제공해주는 매크로이다. 또는 assert.h의 assert함수를 이용해도 좋다. MFC등을 사용한다면 ASSERT등을 사용해도 좋고 Robbins의 SUPER_ASSERT를 사용해도 좋다. 각각 약간씩의 차이점이 있기는 결과는 거의 같다. 그러니 여기서는 CRT를 사용한다는 일관성을 유지하기 위해 _ASSERTE를 사용하도록 하겠다.

단순히 위와같이 의심갈때마다 호출해 주기만 한다면, CRT는 지금까지 등록된 모든 할당된 메모리들을 검사해 문제가 발생했는지를 확인한다. 그럼 어떤 종류의 에러들을 잡아주는지 다음의 예제들을 통해 알아보도록 하자

예제1. 경계를 넘어서서 쓰는 경우

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

{

int *p = new int[10];

p[-1] = 100; // 둘다 모두 오류이다

p[10] = 100;

_ASSERTE( _CrtCheckMemory( ) );

return 0;

}


위의 예제에서는 정수 타입 10개짜리 배열을 할당하고 11번째 멤버에 쓰기를 시도하였다. 이부분에는 지난 강좌에서 알려 드렸듯이 0xfd값이 채워져 있는 영역이다. 주어진 메모리 체크 함수는 0xfd값이 있어야 할 자리에 다른 값이 있는 경우 0을 리턴한다.


예제2. 삭제된 포인터에 접근을 시도하는 경우


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

{

// _CRTDBG_DELAY_FREE_MEM_DF 플랙을 반드시 켜야된다

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF);

int *p = new int[10];

delete [] p;

p[0] = 10;

_ASSERTE( _CrtCheckMemory( ) );

return 0;

}


위 예제에서는 이미 삭제된 포인터를 다시 접근하고 있다. 이것은 디폴트로 비활성화된 플랙을 사용하므로 위의 예제에서처럼 프로그램 시작전에 _CRTDBG_DELAY_FREE_MEM_DF 플랙을 켜줘야한다. 이 플랙이 켜지게 되면 CRT는 삭제 명령(free함수)이 호출되는 경우 바로 삭제처리하지 않는다. 대신 삭제 처리했다는 표시(0xdd값)만을 남겨둔다음 필요할 때 이값이 깨졌는지 검사한다. 디버그 버전이라면 이 플랙은 반드시 켜두도록 한다. 물론 메모리 부하가 약간 더 있겠지만 심각한 오류를 검출하는데는 꼭 필요한 플랙이다. 어차피 디버그 버전은 디버깅이 최고의 목표이니까..


이 두가지 기능만해도 일반적인 프로그래머들이 겪는 대부분의 메모리 문제는 해결된다. 아! 필자가 지금까지 봐온 대부분의 메모리 관련 문제들은 거의 60%이상이 초기화가 되지 않았거나 쓰레기값이 들어있는 포인터 접근 문제였다. 이문제는 위의 함수가 잡아주지 않는다. 그럼 쓰레기값이 들어있는 포인터 접근 문제는 어떻게 해결하겠는가? 아시는 분들은 다 아실것이다 0xC0000005 오류가 바로 정답이다. 또 대부분의 컴파일러의 경우 컴파일하는 도중에 이미 초기화 안된 변수를 사용했다고 여러분들에게 알려줄 것이다.


다음에는 구간과 구간 사이에서 메모리 문제를 발견하는 방법에 대해 다룰 것이다. 전체 프로그램에서 문제를 발견했다면 그 범위를 점차 좁혀나가는 것이 중요하다. 아쉽지만 필자 개인적인 사정으로 인해 조금 늦어질지도 모르겠다.


Memory Leak Check



Visual C++에서는 MFC나 C 런타임 라이브러리 내에서 메모리 누수를 검사할 수 있는 간단한 방법을 제공한다. MFC는 사용자가 특별히 작업해주지 않아도 메모리 누수를 보고해주는 기능이 포함되어 있는 반면, MFC를 사용하지 않는 프로그램들은 메모리 누수를 검사하도록 사용자가 직접 코드를 추가해주어야 한다.


간단히 절차를 말하면, 다음과 같다.


전처리 부분의 가장 위쪽, 보통 PCH 다음에 #define _CRTDBG_MAP_ALLOC를 선언하고, #include “crtdbg.h”를 포함한다.


#include “stdafx.h”
#define _CRTDBG_MAP_ALLOC
#include “crtdbg.h”


그리고, 필요한 함수는 _CrtSetDbgFlag(), _CrtDumpMemoryLeaks(), _CrtSetReportMode() 세가지이다. 먼저, _CrtSetDbgFlag()를 사용하여 기본적인 디버그 설정을 한 다음, 메모리 누수를 검사할 덤프 시점에 _CrtDumpMemoryLeaks()를 호출하는 방식이다. 콘솔 프로그램을 작성한다면, 보통 main() 함수에서 return 이전 시점이 될 것이다.


여기서, 프로그램이 종료되는 위치를 고정적으로 선택할 수 없다면, _CrtDumpMemoryLeaks()를 종료되는 부분에 모두 작성하는 대신, _CrtSetDbgFlag() 함수를 사용할 수 있다. 이 함수의 파라미터 설정에 따라 어느 시점에서 메모리 누수를 검사할 수 있는지 설정하는 것이 가능하다. 예를 들어서, C++의 소멸자를 사용한 메모리 해제는 일반적인 경우라면 메모리 누수라고 보고될 것이다. 즉, 스마트 포인터와 같은 것을 작성하는 도중이라면, 소멸자의 행동까지 추적하지 않기 때문에 메모리 누수라고 보고될 것이다. 이 경우, _CrtSetDbgFlag()의 파라미터를 적절히 설정하는 것으로 메모리 누수 검사 시점을 선택할 수 있다.


_CrtSetReportMode()는 사용해도 그만이고, 사용하지 않아도 그만이다. 중요한 것은 _CrtSetDbgFlag()와 _CrtDumpMemoryLeaks()이다.


예를 든다면, 다음과 같다.


#define _CRTDBG_MAP_ALLOC
#include “crtdbg.h”

int main()
{
    int DbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
    DbgFlag |= _CRTDBG_LEAK_CHECK_DF;
    _CrtSetDbgFlag(DbgFlag);

    char* pMem = new char(64);

    _CrtDumpMemoryLeaks();
    return 0;
}


여기서, _CrtDumpMemoryLeaks()를 프로그램의 종료 시점에서 호출하고 싶다면, DbgFlag에 _CRTDBG_ALLOC_MEM_DF 플래그를 추가로 설정해주어야 한다. 즉, 위의 코드와 같은 경우, _CrtDumpMemoryLeaks() 다음에 힙을 정상적으로 해제하는 코드가 있더라도 메모리 누수를 보고하게 된다. _CRTDBG_ALLOC_MEM_DF 플래그를 설정하면, _CrtDumpMemoryLeaks()를 호출하지 않더라도 Output 윈도우에 메모리 누수 여부를 알려줄 것이다.


MSDN Document : http://support.microsoft.com/kb/601929/ko,
http://msdn.microsoft.com/en-us/library/5at7yxcs(VS.71).aspx

http://enddl22.net/wordpress/?p=2106

'library > CRT' 카테고리의 다른 글

컴파일 옵션  (0) 2013.02.22
메모리 누수 체크  (0) 2011.10.27
errno  (0) 2011.01.08
유니코드를 위한 함수  (0) 2011.01.08
시간과 날짜와 관련된 라이브러리 함수들  (0) 2010.12.15
블로그 이미지

란마12

,


prompt-lvis.reg


'tool' 카테고리의 다른 글

7z 압축파일 자동풀기 실행프로그램 만들기  (0) 2014.10.17
doxygen  (0) 2011.12.06
crash dump  (0) 2011.11.11
WinDbg  (0) 2011.01.30
VC .Net에서 산출물(output/intermediate) 관리하기  (0) 2010.12.23
블로그 이미지

란마12

,

This is a very useful trick if you want to debug in android by WiFi.


1. Connect you phone into USB
2. Open cmd
3. Type "adb tcpip 5555"
4. Remove phone from USB
5. Type "adb connect IP" (Where IP is your phone direction)

Note: To see your phone IP direction just go to wifi settings and click above your connected WiFi.

PD: If you don't want to connect over and over you phone by USB all you have to do is assign an static IP (usually in home network it always get the same so probably this is not needed) and create a little CMD script.

From now all you have to do is start Android Studio and execute the script.

The script would be something like....

adb connect "your IP"
PAUSE

Changing "your ip" for the real one (In my case 192.168.1.35)

If you are looking for some icon to your script could be something like the next:


Hope you like it guys!!





http://justcodeitdown.blogspot.kr/2014/01/wifi-debugging-in-android.html

'mobile > Android' 카테고리의 다른 글

c에서 logcat에 log찍기  (0) 2010.07.28
stlport  (0) 2010.07.26
c와 연동  (0) 2010.07.23
자바프로젝트에서 export한 jar를 안드로이드프로젝트에서 불러오기  (0) 2010.07.22
블로그 이미지

란마12

,

메일 발송

database/MSSQL 2014. 1. 28. 11:08








다음작업을 수행하여 데이터베이스 메일 설치 -> 다음

프로필이름, 설명 적고, 아랫쪽 추가 클릭

계정이름 및 SMTP서버 정보 입력


DECLARE @body1 varchar(100)

SET @body1 = 'Server :'+@@servername+ ' My First Database Email '

EXEC msdb.dbo.sp_send_dbmail

    @profile_name = 'MY_PROFILE_NAME' -- 프로필이름

,    @recipients = 'yonjunhee@gmail.com'

, @copy_recipients = null

, @blind_copy_recipients = null

, @body_format = 'TEXT'

,    @body = @body1 

, @importance = 'Normal'

, @sensitivity = 'Normal'

, @file_attachments = null

,    @query = 'SELECT * FROM [DBNAME].[DBO].TABLE1'

,    @subject = @body1 

,    @attach_query_result_as_file = 1  -- 쿼리문으로 만들어진 파일은 한개

,    @query_attachment_filename = 'SelectQuery.csv' -- 출력형태는 mssql 에서 지원하는 형태가 몇개 있츰 첨부될 파일명 지정

, @query_result_header = 1

, @query_result_width = 32767 -- can go to 32767 for query width

, @query_result_separator = ','

, @exclude_query_output = 0

, @append_query_error = 1

, @query_result_no_padding =1 -- turn off padding of fields with spaces


발송내역 확인

 SELECT * FROM [msdb].[dbo].[sysmail_allitems]


http://blog.naver.com/vfxx?Redirect=Log&logNo=100168933260


'database > MSSQL' 카테고리의 다른 글

데이터 타입과 크기  (0) 2014.08.01
동적쿼리  (0) 2014.07.16
중복데이터 제거  (0) 2013.03.05
원격 접속 허용하기  (0) 2011.07.07
BCP  (0) 2010.06.29
블로그 이미지

란마12

,

자식 컨트롤이 겹칠 때 특정 컨트롤을 맨앞으로 오게 하고 다른 컨트롤과 이벤트나 UI가 겹쳐지지 않게 하는 방법


겹쳐지는 관련 컨트롤 모두에 WS_CLIPSIBLINGS | WS_CLIPCHILDREN 스타일 추가

BringWindowToTop함수 호출

블로그 이미지

란마12

,

PHP로 간단한 문자열을 리턴하는 스크립트를 짜고 브라우저에서 실행해보니..

리턴한 문자열 외에 ' ' + ascii(13) + ascii(10)이 추가된다.

문제는 스크립트 마지막 괄호 ?>까지 실행되면 저런 문제(?)가 있는 듯하다.

괄호 전에 exit해주면 문제 없음.

블로그 이미지

란마12

,

윈도우 명령 줄 스크립트

우선 간단한 명령줄 배치 파일을 살펴보자.

@echo off
rem This is a comment!
echo Hi

@echo off는 거의 모든 명령줄 스크립트에 쓰며 보통 첫번째 줄에 놓는다. @echo off 가 없다면 아래와 같이 명령어 실행 과정을 일일이 보여준다. 보통은 사용자가 원치 않는 행동이다.

c:>a.bat

c:>rem This is a comment!

c:>echo Hi
Hi

rem은 주석 지시자로 생각하면 된다. C++의 // 와 동일한 역할을 한다.

ERRORLEVEL

윈도우 응용프로그램처럼 명령줄 배치 파일에도 종료 코드(exit code)가 있다. C++ 프로그램에선 main 함수의 반환값인 종료 코드를 명령줄 배치에선 오류 수준(ERRORLEVEL)이라 부른다. 일반적인 관례에 따르면 종료 코드 0은 성공을 의미하고 나머지 값은 실패를 뜻한다.

ERRORLEVEL 설정하기

명령줄 배치 스크립트에서 종료 코드를 명시적으로 반환할 땐 exit 명령어를 쓴다.

@echo off
rem This is a comment!
echo Hi
exit /b 0

/b 옵션이 있으면 배치 스크립트를 종료한다. 그렇지 않으면 아예 CMD.exe 프로세스를 종료시키므로 주의한다.

주의! 윈도우 버전에 따라 종료 코드를 반환하는 방식이 다른데 exit /b는 윈도우 2000 부터 도입됐다. 그 이전 버전에 대해 알고 싶다면 Errorlevels를 참고하자.

ERRORLEVEL 확인하기

배치 파일의 성공 여부를 알고자 한다면 명령줄에 다음과 같이 입력한다.

c:>a.bat
Hi!

c:>echo %errorlevel%
0

인자 넘겨받기

인자는 그 순서대로 %0, %1, %2 식으로 지칭하면 된다. 단 %0은 배치 파일의 이름을 나타내는 특수 인자임을 주의한다.

@echo off
echo filename = %0
xcopy /E %1 %2
exit /b 0

이 스크립트는 자신의 이름을 메시지로 내보낸 후 첫 번째 인자로 받은 디렉터리 트리를 두 번째 인자로 받은 경로에 복사한다.

c:>a.bat a a1
filename = a.bat
0 File(s) copied

마지막으로 특별한 인자 지시자 "%"를 소개한다. "%"는 모든 인자를 묶은 문자열을 나타낸다. 위의 코드에선 "a a1"이 된다.

사용자 입력 받기

표준입력장치에서 사용자의 입력을 받아 출력하는 예제를 보면 이해하기 쉽다.

@echo off
rem This is a comment!
set /p name=What is your name? 
echo Your name is %name%.
exit /b 0

이 배치 스크립트를 실행하면 다음과 같은 결과를 얻는다.

c:>a.bat
What is your name? Jay
Your name is Jay.

첫 번째 \”Jay\”는 사용자가 키보드로 입력한 값이다.

변수

SET

SET 명령을 사용하면 변수 선언이 가능하다.

@echo off
rem this is "conditional.bat".
set var1=first variable
echo %var1%

exit /b 0

이 방법의 특징은 스크립트가 종료된 후에도 선언한 변수는 유효하다는 것이다. CMD.exe가 종료되기 전까진 유효하다.

F:WorkspaceWinBatch>conditional.bat
first variable

F:WorkspaceWinBatch>set var1
var1=first variable

스크립트 내에서만 유효한 변수

위의 방법과 달리 스크립트 종료 후에 변수 선언을 무효로 만들려면 setlocal을 이용한다.

@echo off
rem this is "conditional.bat".

setlocal
set var1=first variable
echo in the local: %var1%
endlocal

echo out of the local: %var1%

exit /b 0
F:WorkspaceWinBatch>conditional.bat
in the local: first variable
out of the local:

SETX

SET 로 만들거나 값을 변경한 변수는 명령 줄 프로세스(CMD.exe)가 살아있는 동안만 유효하다. 이러한 제한을 벗어나려면 사용자/시스템 환경 변수를 직접 조작하는 수밖에 없다. SETX 는 이런 기능을 제공한다.

시스템 PATH 값을 조작하기

/M 스위치가 있으면 시스템 환경 변수를 바꾸고, 그렇지 않으면 사용자 환경 변수를 변경한다.

SETX PATH "%PATH%;C:Temp" /M


PATH 값을 조작할 때는 경로 끝에 \"\" 이 붙지 않게 한다. 그래야 오류가 나지 않는다. 다음과 같은 명령은 재앙을 일으킬 수도 있다.

SETX PATH "%PATH%;C:Temp" /M


#### 특수 변수

##### %RANDOM%

0 ~ 32767 사이의 값을 무작위로 뽑아 반환한다. 
c:>echo %RANDOM%
30401
%CD%

현재 작업 디렉터리를 나타낸다.

@echo off
rem D:test.bat 

echo %CD%

C:에서 D:에 있는 test.bat 파일을 실행하면 다음과 같은 결과가 나온다.

C:>D:test.bat
C:
%0 외

%0 계열의 변수는 작업 디렉터리가 하닌 배치 스크립트의 경로를 기준으로 값을 정한다.

UNC 경로일 때
%0 = "\\serverusersmystuffTempMy TestMy Batch File.cmd"
%~0 = \\serverusersmystuffTempMy TestMy Batch File.cmd
%~d0 = \\
%~p0 = serverusersmystuffTempMy Test
%~dp0 = \\serverusersmystuffTempMy Test
드라이브 경로일 때
%0 = "H:TempMy TestMy Batch File.cmd"
%~0 = H:TempMy TestMy Batch File.cmd
%~d0 = H:
%~p0 = TempMy Test
%~dp0 = H:TempMy Test
%DATE% 과 %TIME%

각각 오늘 날짜와 현재 시간을 반환한다.

c:>echo %DATE% %TIME%
2009-10-06 17:56:50.53

서버의 언어 설정에 따라선 포맷이 다르기도 하다.

c:>echo %DATE% %TIME%
Tue 10/06/2009 17:56:50.53

그러므로 %DATE%를 파싱할 땐 특히 주의해야 한다. 아래 코드는 후자(지역 언어: 영어)에서만 제대로 작동한다.

@echo off 
echo %DATE% %TIME%
set MTH=%DATE:~4,2%
set DAY=%DATE:~7,2%
set YR=%DATE:~10,4%
set HR=%TIME:~0,2%
set HR0=%TIME:~0,1%
if "%HR0%"==" " set HR=0%TIME:~1,1%
set MIN=%TIME:~3,2%
set SEC=%TIME:~6,2%
set MYDATE=%YR%%MTH%%DAY%-%HR%%MIN%%SEC%
echo %MYDATE%
그밖의

마이크로소프트 사가 제공하는 Command shell overview 문서를 참고한다.

조건문

if exist 파일이름

파일의 존재 여부를 확인할 때 사용한다.

@echo off
rem this is "conditional.bat".
if exist conditional.bat echo there it is!
if not exist no.bat echo it doesn't exist!
exit /b 0

이 배치 스크립트의 결과는 다음과 같다.

F:WorkspaceWinBatch>conditional.bat
there it is!
it doesn\'t exist!

if defined

변수의 존재 여부를 확인할 때 사용한다.

@echo off
rem this is "conditional.bat".
setlocal
set var1=first variable
if defined var1 echo val1 is there!
if not defined var2 echo val2 is not there!
endlocal 

exit /b 0

이 배치 스크립트의 결과는 다음과 같다.

F:WorkspaceWinBatch>conditional.bat
val1 is there!
val2 is not there!

if 문자열1==문자열2

@echo off
setlocal
set var1=variable
set var2=variable
set var3=some-variable
if %var1% == %var2% (echo var1 equals to var2) else (echo var1 not equals to var2)
if %var1% == %var3% (echo var1 equals to var3) else (echo var1 not equals to var3)
endlocal 
 
exit /b 0

이 배치 스크립트의 결과는 다음과 같다.

F:WorkspaceWinBatch>test.bat
var1 equals to var2
echo var1 not equals to var3
비교 연산자
  • EQU – equal
  • NEQ – not equal
  • LSS – less than
  • LEQ – less than or equal
  • GTR – greater than
  • GEQ – greater than or equal
대소문자 구분

기본적으로 문자열 비교시 대소문자 구분 을 한다. 만약 대소문자의 구분 없이 비교하고 싶다면 /I 옵션을 주면 된다.

@echo off
setlocal
set var1=variable
set var2=variable
set var3=VARIABLE
if %var1% EQU %var2% (echo var1 equals to var2) else (echo var1 not equals to var2)
if %var1% EQU %var3% (echo var1 equals to var3) else (echo var1 not equals to var3)
if /I %var1% EQU %var3% (echo var1 equals to var3) else (echo var1 not equals to var3)
endlocal 
 
exit /b 0

이 배치 스크립트의 결과는 다음과 같다.

F:WorkspaceWinBatch>test.bat
var1 equals to var2
echo var1 not equals to var3
var1 equals to var3

if errorlevel

{{미완성}}

for 를 이용한 순회

주의! 변수 이름은 대소문자를 구분한다!

문자열, 명령 출력값 파싱하기

/f 옵션을 쓰면 파일, 문자열, 명령 출력값에서 필요한 텍스트를 검사하고 찾아낼 수 있다. 이를테면,

for /f %%a in ('cd') do set MYROOT=%%a

이 배치 파일은 명령줄에서 cd를 실행시키고 그 결과(현재 디렉터리의 경로) %%a 변수에 저장한다. 그런 후 MYROOT라는 환경변수에 현재 디렉터리의 경로를 입력한다.

참고 문헌

*Microsoft Windows XP – For

문자열 다루기

문자열 추출

문자열의 인덱스 값을 지정해 부분 문자열을 뽑아낼 수 있다. 대부분의 부분 문자열 메서드와 마찬가지로 첫 매개변수는 시작 지점이고 두 번째 매개변수는 문자열의 길이이다.

예제 1
@echo off

set str=politic
echo.%str%
set str=%str:~0,4%
echo.%str%
politic
poli
예제 2
@echo off

echo.Date   : %date%
echo.Weekday: %date:~0,3%
echo.Month  : %date:~4,2%
echo.Day    : %date:~7,2%
echo.Year   : %date:~10,4%
Date   : Sat 03/11/2006
Weekday: Sat
Month  : 03
Day    : 11
Year   : 2006
예제 3
@echo off

set str=politic
echo.%str%
set str=%str:~1,-1%
echo.%str%
politic
oliti
예제 4
set str=politic
echo.%str%
set str=%str:~-4%
echo.%str%
politic
itic

참고 문헌

고급 기법

래퍼 파일

만약 msbuild.exe를 쓸 생각이라면 어떨까? 닷넷 프레임워크의 버전마다 msbuild.exe 바이너리가 따로 있으며 그 경로는 매우 복잡하다. 이런 경우엔 다음과 같이 배치 파일을 만들면 된다.

@echo off
"C:WINDOWSMicrosoft.NETFramework64v3.5msbuild.exe" %*

이게 끝은 아니다. msbuild.exe의 종료 코드를 받아 전달해야 완전한 래퍼 파일이 된다.

rem NewMSBuild.bat
@echo off

C:WINDOWSMicrosoft.NETFramework64v3.5msbuild.exe %*
exit /b %errorlevel%

이보다 복잡한 스크립트라면 고려할 점이 또 있다. 배치 스크립트에선 환경변수를 조작하는 일이 흔하다. 그러나 스크립트 종료 후에 환경 설정을 원래대로 돌리고 싶은 게 보통이다. 여러 방법이 있지만 가장 간단한 방법만 보자.

rem MyMSBuild.bat
@echo off

CMD.exe /K NewMSBuild.bat %*
SET ERR_LEVEL=%errorlevel%
exit /b %ERR_LEVEL%

이 예제는 환경 변수를 조작하는 코드는 모두 NewMSBuild.bat에 있다고 가정한다. 새 인터프리터를 띄우고 그 안에서 환경 변수를 조작한다. 스크립트를 다 실행한 후 인터프리터가 종료되고 그와 동시에 스크립트 안에서 조작한 환경 변수는 모두 날아간다.

현재 디렉터리 #1

현재 디렉터리를 구하는 방법은 다음과 같다.

@echo off

rem little complicated 
SETLOCAL
for /f %%a in (\'cd\') do set MYROOT=%%a
echo %MYROOT%
ENDLOCAL

rem more easiler way
echo %CD%

두 번째는 시스템이 제공하는 의사 변수인 %CD%를 사용한다. %CD%가 없는 시스템에선 첫 번째 방법처럼 CD 명령을 실행시켜 그 출력값을 가져오면 된다.

현재 디렉터리 #2

CD 명령이나 %CD% 의사 변수를 사용하는 방법엔 문제가 있다.

@echo off
rem F:WorkspaceWinBatchdirshow.bat

echo this is %%cd%%  %cd%
echo this is %%~dp0 %~dp0

F:WorkspaceWinBatch 폴더에 dirshow.bat 란 배치 파일이 있다고 하자. dirshow.bat를 F:WorkspaceWinBatch에서 실행하면 예상했던 출력값이 나온다.

F:WorkspaceWinBatch>dirshow.bat

F:WorkspaceWinBatch>
this is %cd%  F:WorkspaceWinBatch
this is %~dp0 F:WorkspaceWinBatch

그러나 C:에서 dirshow.bat를 실행시키면 다른 결과가 나온다.

c:>F:WorkspaceWinBatchdirshow.bat
this is %cd%  c:
this is %~dp0 F:WorkspaceWinBatch

CD는 명령을 실행한 경로를 반환한다. 그에 반해 %~dp0%은 배치 스크립트 파일의 경로를 반환한다. 상황에 맞는 방법을 선택하면 된다.

부모 디렉터리

제일 쉬운 방법은 %~dp0% 를 이용하는 것이다.

@echo off
rem D:WorkspaceWinBatchdirshow.bat

echo this is %%~dp0 %~dp0..

이 방법의 단점은 경로가 지저분하다는 점이다.

D:WorkspaceWinBatch..

조금 더 깔끔한 경로를 원한다면 이렇게 한다.

@echo off
rem F:WorkspaceWinBatchdirshow.bat

for %%? in ("%~dp0..") do echo %%~f?
D:Workspace 

출처: http://andromedarabbit.net/wp/%EC%9C%88%EB%8F%84%EC%9A%B0-%EB%AA%85%EB%A0%B9-%EC%A4%84-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8/

블로그 이미지

란마12

,

저축

yonjh/재테크 2013. 8. 20. 15:34

1. 절세


1) 생계형: 만60세 이상, 3천만원 한도 비과세


2) 세금우대

a. 20~59세: 1천만원 한도 9.5%

b. 만60세 이상: 3천만원 한도 9.5%


3) 단위농협, 신협, 새마을금고등의 조합원

a) 3천만원한도 1.4%(농특세), 금융종합과세에서 제외

b) 출자금통장 1천만원 한도 비과세(예금자 보호안됨)


2. 만기이연

 1) 만기 전 전체 기간 중 2/3회차이상 불입되어야 함

 2) 만기 후 최대 이연 가능 기간은 전체 기간의 1/2

 3) 예를 들어, 10만원 불입 3년짜리 적금인 경우

    - 만기 전에 24개월치 이상 불입되어 있어야 함

    - 만기 후 최대 18개월까지 연장 가능

'yonjh > 재테크' 카테고리의 다른 글

금융소득 종합과세  (0) 2018.10.25
펀드투자  (0) 2015.06.05
임대주택의 전환보증금  (0) 2013.06.11
마이너스 통장  (0) 2013.03.04
블로그 이미지

란마12

,

삽질 기록

tool/VS10 2013. 8. 19. 22:23

릴리즈 모드에서 다음과 같은 경고 발생 시 

/GL로 컴파일한 MSIL .netmodule 또는 모듈이 있습니다. /LTCG를 지정하여 링크를 다시 시작하십시오. /LTCG를 링크 명령줄에 추가하면 링커 성능이 향상됩니다.

프로젝트 속성 -> 구성 속성 -> 일반 -> 전체 프로그램 최적화: 링크 타임 코드 생성 사용 선택



라이브러리 디렉터리 설정방식이 두가지이다.

1. 구성속성 -> VC++ 디렉터리 -> 라이브러리 디렉터리

2. 링커 -> 일반 -> 추가 라이브러리 디렉터리(/LIBPATH)

솔루션안에 정적라이브러리 프로젝트와 EXE프로젝트가 같이 있을 때

EXE프로젝트들은 2번에 추가로 경로를 명시해주지 않으니 라이브러리 파일들을 찾지 못하는 현상이 발생



정적 라이브러리 쪽의 클래스: class __declspec(dllexport) A{...

응용프로그램 쪽의 클래스: class __declspec(dllimport) A{...

릴리즈모드에서 컴파일 시 error LNK2001: "__declspec(dllimport) public: __thiscall...  발생하여

두 프로젝트 모두 속성 -> 일반 -> 전체 프로그램 최적화: 전체 프로그램 최적화 안 함

으로 설정하니 오류 안남



프로젝트의 필터정보는 *.vcxproj.filters에 저장. 그냥  프로젝트파일(*.vcxproj)만 복사하면 필터정보가 누락되어 트리에서 헤더와 소스파일이 구분없이 통으로 나열됨.

디버그 설정 정보(실행인자 등)는 *.vcxproj.user에 저장. 이 파일은 SVN에서 관리되지 않음.


디버그 정보가 없는 것처럼 개체를 링크합니다. 경고 발생시

1. "구성 속성" -> "C/C++" -> "일반" -> "디버그 정보 형식" : "프로그램 데이터베이스(/Zi)"

2. "구성 속성" -> "C/C++" -> "코드 생성" -> "최소 다시 빌드 가능" : "아니요(/Gm-)"

3. "구성 속성" -> "C/C++" -> "명령줄" -> "추가 옵션"에 "/Ylsymbol"를 입력
4. "구성 속성" -> "C/C++" -> "일반" -> "전체 프로그램 최적화": "아니요"


블로그 이미지

란마12

,

WDK 샘플 설치 삽질기

etc 2013. 7. 28. 16:18

1. WIN7 64 인데 32용으로 컴파일/설치

 1) 프린터 드라이버 삭제

  가. windows폴더 아래 bitmap.dll파일 위치 검색

   가) C:\Windows\System32\DriverStore\FileRepository\bitmap.inf_amd64_neutral_d515dd8cf86fffaa\bitmap\amd64

   나) C:\Windows\System32\spool\drivers\x64\3

   다) 가)항은 수동삭제, 나)항은 권한문제로 삭제되지 않아 http://technet.microsoft.com/en-us/library/cc730875.aspx 참조하여 삭제

        pnputil.exe -e로 검색 

-----------------------------------------------------

게시된 이름 :            oem92.inf

드라이버 패키지 공급자 :   Microsoft WDK Sample

클래스 :                     프린터

드라이버 날짜 및 버전 :   6/07/2001 1.0.0.1

서명자 이름 :

------------------------------------------------------


공급자가 Microsoft WDK Sample로 검색되는 드라이버 모두 삭제


        pnputil.exe -d Oem92.inf 삭제


드라이버 설치 시 마지막 단계에서 기존 설치된 드라이버 사용하겠냐는 메시지

bitmap.inf_amd64_neutral_d515dd8cf86fffaa.cab

'etc' 카테고리의 다른 글

윈도우 2003서버에서 작업스케줄러가 작동하지 않는다.  (0) 2015.01.30
DIR vs PATH  (0) 2015.01.28
ADO 문제(오류번호: 80004003)  (0) 2012.07.10
FTP vs HTTP  (0) 2011.04.14
파일날짜 변경 시점  (0) 2010.07.09
블로그 이미지

란마12

,