'컴파일러 옵션'에 해당되는 글 1건

320x100

[VC6] 컴파일러 옵션 [펌]

Posted on 2010. 1. 29. 15:35
Filed Under Visual C++

<출처: http://tong.nate.com/tigglet/42353507>

 

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 overwritememory underwrite를 체크할 수 있게 한다. ( "0xFDFDFDFD" 즉 디버그 모드에서는 메모리 할당시에 양쪽에 각각 4 byte 의 공간이 마킹하기 위해서 추가적으로 할당이 된다. )
  • 메모리 할당시 소스코드 상에서의 위치를 알아 내는데 도움이 되도록 소스코드의 파일 이름과 해당줄을 추적을 위해서 넣어 놓는다.

 

 

릴리즈 모드에서 디버깅 하기 #1'

 

 설정을 변경하면 디버깅은 잘되나 배포판을 만들 경우에는 변경된 옵션을 환원하고 빌드하자.

자주 써야 할 경우 빌드 타입을 하나 더 만들어서 사용하는 것도 한가지 방법이다.

 

 

vs 6.0 기준

  1. Project/Settings/Project Setting"을 선택.
  2. C/C++“ 탭에서 ”General" 카테고리를 선택해서 "Optimizations"을 “Disable(Debug)"로 선택하고 “Debug info" 항목을 ”Program Database“로 수정.
  3. "Link" 탭에서 “Debug" 카테고리를 선택하면 ”Debug info" 항목이 있는데 여기서 "Microsoft format"을 선택.
  4. Link" 탭에있는 ”Project Options" 박스에 들어 있는 내용의 맨 끝에 "/OPT:REF"를 추가 한다.
  5. 반드시 “Rebuild All"로 제 컴파일을 한다.

 

vs .net 기준

  1. 솔루션 탐색기에서 프로젝트를 선택한 다음 메뉴의 “프로젝트/ XXX 속성"을 선택.
  2. C/C++의 일반 항목중에서, 디버깅 정보 형식을 “사용안함"에서 “편집하며 계속하기를 위한 프로그램 데이터베이스(/ZI)"로 변경.
  3. C/C++의 최적화 항목중에서, 최적화를 “속도 최대화(/O2)" 혹은 "크기 최소화(/O1)”등에서 “사용안함(/Od)"로 변경.
  4. C/C++의 최적화 항목중에서, 인라인 함수 확장을 “__inline만 확장(/Ob1)"  혹은 "적합한것 모두(/Ob2)"등에서 "기본값"으로 변경.링링커의 디버그 항목중에서, 디버그 정보 생성을 “아니요”에서 “예(/DEBUG)"로 변경
  5.  

 

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

그리고

  1. WinMain( ... )
  2. {

    1. _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    2. .
    3. .
    4. .
  3. };

위와 같이 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

순수 가상 함수를 파괴자 등에서 호출하여 생기는 오류 검출 방법.

 

  1.  _set_purecall_handler(_purecall_handler function);

 

위의 함수를 사용하여 순수 가상 함수 호출시 임의의 오류 처리 함수를 호출하도록 하여 해당 부분을 검출해낼수 있다.

아래와 같이 설정하였다면 순수 가상 함수가 호출되는 순간 assert 가 호출되므로 해당 부분의 call-stack 을 확인해보자.

 

  1. void my_purecall_handler(void)
  2. {

    1. assert(0 && "pure virtual function call !!!");
    2. printf("pure virtual function call !!!");
  3. }
  4.  
  5. void main(int argc, char* argv[])
  6. {

    1. _set_purecall_handler(my_purecall_handler);
    2.  
  7. }

 

 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"
반응형

About

by 쑤기c

반응형