'컴파일러 옵션'에 해당되는 글 1건
- 2010.01.29 [VC6] 컴파일러 옵션 [펌]
[VC6] 컴파일러 옵션 [펌]
Posted on 2010. 1. 29. 15:35
Filed Under Visual C++
Compiler options for finding Bugs #1
Compiler Options |
의미 |
/W4 |
Warning Level을 최대로 하여 컴파일 ( 모든 빌드 타입에 가능 ) |
/D "_DEBUG" |
Assetion, Trace 같은 디버깅용 코드가 컴파일시 포함되록 만든다. ( 디버그 빌드에서만 ) |
/GZ |
생성시에 초기화 되지 않는 변수를 특정 값으로 채워 흔히 디버그에서는 나타나지 않고 릴리즈 빌드에서 나타나는 에러를 사전에 검사할 수 있게 하여 디버그에 도움이 되게 함. ( 디버그 빌드에서만 ) |
/Od |
최적화하지 않는다. 코드를 디버그에 적합하게 만든다. ( 디버그 빌드에서만 ) |
/GF |
실행 파일에 들어갈 스트링이 중복될 경우 이를 제거, 공동으로 사용되는 이 스트링이 할당된 메모리를 읽기 전용으로 설정하여 우발적인 메모리 쓰임으로 부터 보호함. ( 정적 문자열.. )
char *s = "This is a character buffer"; char *t = "This is a character buffer";
위와 같은 경우 같은 스트링이므로 스트링을 서로 공유 함. ( 릴리즈 모드에서 명시적으로 사용시 ) |
/Gf |
실행파일에 들어갈 스트링을 공유하는 것은 위와 같으나 우발적인 메모리 쓰임으로 부터 보호 하지 않음. |
/ZI |
디버깅 심벌용 프로그램 데이터베이스를 만듬. 디버그로 실행시에 코드를 편집후 연속해서 디버깅이 가능하게 정보를 관리. ( 디버그 빌드에서만 ) |
/Zi |
디버깅 심벌용 프로그램 데이터베이스를 만듬. ( 릴리즈 빌드에서만 ) |
Compiler options for a debug build #1
Linker Options |
의미 |
/MDd, /MLd, /MTd |
디버그 런타임 라이브러리 사용. |
/Od |
최적화하지 않는다. |
/D "_DEBUG" |
디버그용 코드가 컴파일 되게 한다. |
/ZI |
편집, 연속 디버깅이 가능하게 디버그용 데이터배이스를 만듬. |
/GZ |
디버그 빌드에서의 흔한 실수로 릴리즈에서 나타나는 에러를 디버그모드에서 검출. |
/Gm |
빌드 시간을 재빌드시에 감축시키기. |
Compiler options for a release build #1
Linker Options |
의미 |
/MD, /ML, /MT |
릴리즈 런타임 라이브러리 사용. |
/O1 or /O2 |
속도 최적화나 사이즈 작게 최적화 같은 것을 가능하게. |
/D "NDEBUG" |
디버그용 코드가 컴파일되지 않게 함. |
/GF |
중복된 문자열을 방지, 읽기 전용으로 데이터를 보호함. |
디버그 런타임 라이브러리 사용시 특징 #1
-
디버그 런타임 라이브러리는 메모리 할당을 추적하고 메모리 누수를 점검한다.
-
힙에서 새로이 메모리 할당되어 초기화 되지 않은 데이터에 "0XCD"의 바이트 패턴으로 써놓는다. ( ex : 0xCDCDCDCD )지역 변수인 경우, 초기화 되지 않은 데이터에 "0XCC“의 바이트 패턴으로 써놓는다. ( ex : 0xCCCCCCCC, “/GZ" 컴파일러 옵션 사용시, 미사용시에는 디버그 모드에서 0 로 초기화 함 - 이것은 잠제적인 버그 유발 가능성이 많다. )
-
힙에서 메모리 할당이 해제될 경우에 “0XDD"의 바이트 패턴으로 표시를 하여 해제된 메모리라고 알 수 있도록 표시한다. ( 0xDDDDDDDD 혹은 0xFEEEFEEE )
-
할당된 메모리 버퍼의 양쪽 끝 부분에 4byte 로 “0XFD"의 바이트 패턴으로 표시를 해둬서 memory overwrite나 memory underwrite를 체크할 수 있게 한다. ( "0xFDFDFDFD" 즉 디버그 모드에서는 메모리 할당시에 양쪽에 각각 4 byte 의 공간이 마킹하기 위해서 추가적으로 할당이 된다. )
-
메모리 할당시 소스코드 상에서의 위치를 알아 내는데 도움이 되도록 소스코드의 파일 이름과 해당줄을 추적을 위해서 넣어 놓는다.
릴리즈 모드에서 디버깅 하기 #1'
설정을 변경하면 디버깅은 잘되나 배포판을 만들 경우에는 변경된 옵션을 환원하고 빌드하자.
자주 써야 할 경우 빌드 타입을 하나 더 만들어서 사용하는 것도 한가지 방법이다.
vs 6.0 기준
-
“Project/Settings/Project Setting"을 선택.
-
”C/C++“ 탭에서 ”General" 카테고리를 선택해서 "Optimizations"을 “Disable(Debug)"로 선택하고 “Debug info" 항목을 ”Program Database“로 수정.
-
"Link" 탭에서 “Debug" 카테고리를 선택하면 ”Debug info" 항목이 있는데 여기서 "Microsoft format"을 선택.
-
“Link" 탭에있는 ”Project Options" 박스에 들어 있는 내용의 맨 끝에 "/OPT:REF"를 추가 한다.
-
반드시 “Rebuild All"로 제 컴파일을 한다.
vs .net 기준
-
솔루션 탐색기에서 프로젝트를 선택한 다음 메뉴의 “프로젝트/ XXX 속성"을 선택.
-
C/C++의 일반 항목중에서, 디버깅 정보 형식을 “사용안함"에서 “편집하며 계속하기를 위한 프로그램 데이터베이스(/ZI)"로 변경.
-
C/C++의 최적화 항목중에서, 최적화를 “속도 최대화(/O2)" 혹은 "크기 최소화(/O1)”등에서 “사용안함(/Od)"로 변경.
-
C/C++의 최적화 항목중에서, 인라인 함수 확장을 “__inline만 확장(/Ob1)" 혹은 "적합한것 모두(/Ob2)"등에서 "기본값"으로 변경.링링커의 디버그 항목중에서, 디버그 정보 생성을 “아니요”에서 “예(/DEBUG)"로 변경.
-
Registers And Pseudo-registers #1
Register값은 “Registers" 윈도우에서 확인이 가능하지만 단순하고 값만을 알수 있다. 이 값들을 ”Address(Watch)" 박스에서도 확인이 가능하며 여러 부가 기능과 같이 쓸수 있다.
예를 들어 EAX의 값을 확인 해볼려고 하면 Watch 항목에 “@EAX"혹은 ”@eax"와 같이 대소문자를 구분하지 않고 넣으면 이 래지스터의 값을 확인 할 수 있다.
또한 Pseudo-register"의 값또한 확인 할수 있는데. "@ERR"의 Pseudo-register 값은 매우 유용하게 사용할 수 있는데 이 값이 GetLastError의 값을 나타내기 때문이다. 만약 “@ERR,hr"이라고 입력한다면 Win32의 에러코드에 해당하는 택스트를 보여 줄것이다.
Pseudo-register |
의미 |
@ERR |
GetLastError API로 알 수 있는 가장 최근에 반환된 에러 코드를 보여줌 |
@CLK |
누적시간(MicroSecond)을 보여줌. |
@TIB |
TIB의 주소를 보여줌. |
Pseudo-registers that the Watch window supports #1
Register |
사용(용도) |
@EAX |
일반 용도, 함수의 return 값으로 사용 |
@EBX |
일반 용도 |
@ECX |
일반 용도, 오브젝트의 this 포인터로 사용. |
@EDX |
일반 용도, 64비트의 return값의 경우 상위 값의 반환에 사용. |
@ESI |
메모리 이동과 비교 연산시의 원본 메모리 |
@EDI |
메모리 이동과 비교 연산시에 대상 메모리 |
@EIP |
명령 포인터 ( 코드의 현제 위치 ) |
@ESP |
스텍 포인터 ( 스텍의 현제 위치 ) |
@EBP |
스텍 배이스 포인터 ( 현제 스텍 프레임의 바닥 ) |
@EFL |
비교나 수학 연산을 위한 플래그 비트 |
@CS |
Code segment |
@SS |
Stack segment |
@DS |
Data segment |
@ES |
Extra segment |
@FS |
Another extra segment, used to point to the TIB |
@GS |
Yet another extra segment |
Watch Window Formatting Symbols #1
Watch 윈도우는 변수의 값을 볼수 있게 해주는데, 값을 십진수나 16진수로서 확인할 수 있다. 16진수는 팝업 메뉴에서 “Hexadecimal Display"를 선택하면 볼수 있다. 이 이외에도 여러 가지 옵션을 주어서 사용할 수 있는데 이들은 Watch Window에 등록되는 변수명 뒤에 ","를 삽입하고 그뒤에 옵션을 주어 사용할 수 있다.
Symbol |
Format |
Example |
Output |
d, i |
부호있는 10진 정수 |
-42,d |
-42 |
u |
부호없는 10진 정수 |
42,u |
42 |
o |
부호없는 8진 정수 |
42,o |
052 |
x |
16진 정수 |
42,x |
0x0000002a |
X |
16진 정수 |
42,X |
0x0000002A |
h |
Short prefix for d,i,u,o,x |
42,hx |
0x002a |
f |
실수 |
1.5,f |
1.500000 |
e |
부호 있는 과학용 표기 |
1.5,e |
1.500000e+000 |
g |
Compact float |
1.5,g |
1.5 |
c |
문자 |
42,c |
'*' |
s |
ANSI 문자열 |
"bugs",s |
"bugs" |
su |
UNICODE 문자열 |
"bugs",su |
L"bugs" |
st |
기본 문자열형 ( s, su중에서 ) |
"bugs",st |
"bugs" |
hr |
HRESULT, Win32 error code |
0x06,hr |
The handle is invaid |
wm |
Wndows message number |
0x01,wm |
WM_CREATE |
[digits] |
배열 |
s,5 |
배열 5개의 항목 표시 |
디버깅에 도움이 되는 메모리 마킹 패턴 #1'
Byte Pattern |
의미 |
0xCCCCCCCC |
초기화 되지 않은 stack 메모리 |
0xCDCDCDCD |
초기화 되지 않은 heap 메모리 |
0xDDDDDDDD |
힙에서 해지된 메모리 영역 |
0xFDFDFDFD |
힙에 할당된 메모리 블록 양쪽 4byte의 공간 마킹 |
0xABABABAB |
LocalAlloc()로 할당된 메모리 |
0xBAADF00D |
LocalAlloc(LMEM_FIXED, …)로 할당된 메모리 |
0xFEEEFEEE |
HeapFree()로 해지된 상태 |
가끔 오류가 발생했을 경우에 만날수 있는 magic number. ( 디버깅 모드에서만 byte pattern 으로 마킹됨. )
non-MFC 프로젝트에서 메모리 릭(Memory Leck) 검출
mfc 프로젝트에서는 DEBUG_NEW 가 기본적으로 제공되므로 메모리 릭을 검출하기가 용의하다. 하지만 일반 프로젝트에서는 추가적인 설정이 필요하다.
// CRT's memory leak detection
#if !defined(_AFXDLL)
#include <windows.h>
#include <crtdbg.h>
#if defined(DEBUG) | defined(_DEBUG)
#if !defined(DEBUG_NEW)
#define DEBUG_NEW new(_CLIENT_BLOCK, __FILE__, __LINE__)
#endif
#endif
#endif
위와 같은 코드를 기초 인클루드 파일에 추가하면 된다. ( 예를 들어 StdAfx.h 와 같은 곳에.. )
그리고 아랫 내용을 cpp 파일의 상단(인클루드 아랫 부분)에 추가하면 된다.
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
그리고
- WinMain( ... )
-
{
- _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
- .
- .
- .
- };
위와 같이 App 최초 구동시 메모리 릭 검출 디버깅 옵션을 켜준다.
그러면 디버그 모드로 실행 했을 경우 App 종료시 output 창에 메모리 릭 발생시 메모리 릭 정보가 해당 소스 파일과 라인등 정보와 함께 출력되는 것을 볼수 있을 것이다.
실수 연산 오류 발생시 Exception 발생 시키기 #2
int stat = _controlfp(0, 0);
stat &= ~(EM_ZERODIVIDE);
_controlfp(stat, MCW_EM);
와 같이 EM_ZERODIVIDE 옵션을 추가하였다면 0으로 나눌 경우 해당 코드 부분에서 exception이 발생하므로 발생 부분을 즉시 확인할 수 있는 효과가 있다. 기타 다른 옵션은 MSDN 에서 _controlfp를 찾아서 확인하자.
Special Floating-Point Values and Their Representations #3
Value |
Hex |
Signed 32-Bit Int |
Name |
-1.#QNAN |
FFFFFFFF ~ FF800001 |
-1 ~ -8388607 |
Negative NaNs |
-1.#INF |
FF800000 |
-8388608 |
-∞ |
0 |
|
|
|
0 |
|
|
|
|
|
|
+∞ |
+1.#QNAN |
7F800001 ~ 7FFFFFFF |
2139095041 ~ 2147483647 |
Positive NaNs |
*, 1.#QNAN 의 경우 1.#INF ( 무한대의 값 ) 으로 연산시에 발생함.
Pure virtual Function Call #4
순수 가상 함수를 파괴자 등에서 호출하여 생기는 오류 검출 방법.
- _set_purecall_handler(_purecall_handler function);
위의 함수를 사용하여 순수 가상 함수 호출시 임의의 오류 처리 함수를 호출하도록 하여 해당 부분을 검출해낼수 있다.
아래와 같이 설정하였다면 순수 가상 함수가 호출되는 순간 assert 가 호출되므로 해당 부분의 call-stack 을 확인해보자.
- void my_purecall_handler(void)
-
{
- assert(0 && "pure virtual function call !!!");
- printf("pure virtual function call !!!");
- }
- void main(int argc, char* argv[])
-
{
- _set_purecall_handler(my_purecall_handler);
- }
References
- #1 : Debugging Windows Programs: Strategies, Tools, and Techniques for Visual C++ Programmers / Everett N. McKay, Mike Woodring / Addison-Wesley / 2000
- #2 : Game Programming Gems ?
- #3 : Game Programming Gems 6
- #4 msdn "Run-Time Library Reference : Error-Handling Routines"