45
DEBUGGING? Lusain. Kim

당신의 디버깅에 니코니코니

Embed Size (px)

Citation preview

Page 1: 당신의 디버깅에 니코니코니

DEBUGGING?

Lusain. Kim

Page 2: 당신의 디버깅에 니코니코니

디버깅이란?

Page 3: 당신의 디버깅에 니코니코니

디버깅이란?

디버깅 : 프로그램에 버그가 발생했을 때 이것을 잡는 행위

버그 : 프로그램 실행 중 예기치 않은 오류가 발생한 상황

컴파일 에러 : 여기서 설명하지 않습니다. 파이팅!

런타임 에러 : 이제부터 설명 할게요.

Page 4: 당신의 디버깅에 니코니코니

Hello, Debugging

알고 쓰셨어요? Visual Studio에서 제공하는 디버깅 방법

Page 5: 당신의 디버깅에 니코니코니

디버깅의 기초 : 들어가기 전에

디버깅은 항상 ‘Debug’ 상태에서 작업! ‘Release’ 상태에서는코드최적화를 하기 때문에 정상적인 디버깅이 어렵다!

‘Release’ 상태에서 디버깅 하는 방법 : LOG 띄우기, 문자열 출력…

디버깅은Visual Studio에서 하고 끝이 아니다! 개발 환경에서는 발생하지 않는 문제가 존재할 수 있음

따라서 배포 환경에서의 테스트는 필수불가결

Visual Studio 재배포 패키지가 설치되지 않은 환경은 프로그램의 정상 동작을 보장 못함!

배포하기 전에 여러 환경에서 프로그램을 테스트 하는 것이 중요!

Page 6: 당신의 디버깅에 니코니코니

디버깅의 기초 : 중단

프로그램을 디버깅할 때 이런 문제가 발생할 경우,

(Press Retry to debug the application)

을 눌러 디버깅해야 원인을 알 수 있음.

Page 7: 당신의 디버깅에 니코니코니

디버깅의 기초 : 호출 스택

디버깅 중인 프로그램을 일시 중지했을 때 어떤 경로로 중단된 위치까지 코드가 실행됐는지 확인할 수 있는매우유용한창

아래 호출 스택의 경우, WinMain > CGameFramework::FrameAdvance

> CGameFramework:: AnimateObject >MainStage::AnimateObject

형태로 접근한 상태.

더블 클릭으로 해당 스택으로 이동 가능. 이동한 위치의 변수 값도 확인 가능.

Page 8: 당신의 디버깅에 니코니코니

디버깅의 기초 : 중단점

중단점(F9)

빨간 원 형태로 표시. 해당 위치를 클릭하여 생성/ 해제 가능

오른쪽 스크롤 바에 갈색으로 표시

디버깅(F5) 중 중단점이 찍힌 위치에서 일시정지

중단점에 의한 일시정지는 별도의 조작이 없다면 해당 줄 시작 직전.

(바로 직전 줄까지 실행된 상태)

Page 9: 당신의 디버깅에 니코니코니

디버깅의 기초 : 중단점++

[디버그(D) > 창(W) > 중단점(B)] 를 통해 중단점 일괄 관리가 가능

중단점 창에서 할 수 있는 일 : 중단점 새로 만들기

비활성화

중단점 삭제

중단 조건 입력 : 조건이 참인 경우와 값이 변경된 경우 중단.

단, 중단 조건은 연산자 오퍼레이터를 지원하지 않음

+ Tip )

Page 10: 당신의 디버깅에 니코니코니

디버깅의 기초 : 중단점++

중단점 창에서 할 수 있는 일(계속) : 적중 횟수에 따른 처리 : 중단점의 실행 횟수에 따라 중단 가능.

적중될 때 계속 실행하되 출력 창에 메시지 표시 가능.

Page 11: 당신의 디버깅에 니코니코니

디버깅의 기초 : 중단점++

중단점 창에서 할 수 있는 일(계속) : 적중 횟수에 따른 처리 : 중단점의 실행 횟수에 따라 중단 가능.

적중될 때 계속 실행하되 출력 창에 메시지 표시 가능.

필터 : 적중되는 코드의 호출 위치에 따라 중단 여부 결정.

Page 12: 당신의 디버깅에 니코니코니

디버깅의 기초 : 중단점++

중단점 창에서 할 수 있는 일(계속) : 적중 횟수에 따른 처리 : 중단점의 실행 횟수에 따라 중단 가능.

적중될 때 계속 실행하되 출력 창에 메시지 표시 가능.

필터 : 적중되는 코드의 호출 위치에 따라 중단 여부 결정.

위치 : 중단될 줄과 문자(몇 번째 문자에서 멈출지) 설정.

Page 13: 당신의 디버깅에 니코니코니

디버깅의 기초 : 중단점++

중단점 창에서 할 수 있는 일(계속) : 적중 횟수에 따른 처리 : 중단점의 실행 횟수에 따라 중단 가능.

적중될 때 계속 실행하되 출력 창에 메시지 표시 가능.

필터 : 적중되는 코드의 호출 위치에 따라 중단 여부 결정.

위치 : 중단될 줄과 문자(몇 번째 문자에서 멈출지) 설정.

Visual Studio 2015에서는 더욱 발전된 형태로 제공

Page 14: 당신의 디버깅에 니코니코니

디버깅의 기초 : 지금 얘 값이 어떻게 되지?

[디버그(D) > 창(W) > 자동(A), 지역(L), 조사식(W)] 등을 통해 확인 가능※ 디버깅 중이 아닐 경우 표시되지 않음!

중단 중인 위치에서의 객체 또는 변수의 상태를 알 수 있음. 자동 : 코드의 현재 줄과 이전 줄에 사용된 변수를 알아서 잘 표시.

지역 : 현재 범위의 지역 변수를 표시. 가장 기본적으로 사용하는 상태.

조사식 : 원하는 값을 ‘이름’ 필드에 입력하여 값을 확인 가능. 전역 값 확인에 유용. 디버깅할 때 가장 많이 들여다 볼 창

Page 15: 당신의 디버깅에 니코니코니

디버깅을 할 때, 진입점(entry point, 대체로 main())부터 한 줄씩 실행이 가능! F11 : 한 단계씩 코드 실행

F10 : 프로시저 단위 실행

Shift + F11 : 프로시저 나가기

Alt + Num *(NumPad의 * 키) : 다음 문(현재 커서 위치) 표시

Ctrl + F10 : 텍스트 편집 중 현재 캐럿이 위치한 줄까지 디버깅 후 일시 정지

현재 커서 위치

Visual Studio 2015에서는 일시 중지부터

다음 일시 중지 시점까지의경과시간표시.

디버깅의 기초 : 한 줄씩 볼래요!

Page 16: 당신의 디버깅에 니코니코니

가끔, 현재까지 실행된 상태로 몇 줄 전의 코드를 실행하면 어떻게 되는지 확인해야할 경우가 존재

현재 커서 위치 아이콘( )을 실행을 원하는 줄로 드래그하여 계속 디버깅

사용 목적 :

해당 디버깅에 원하지 않는 실행 구문을 건너뛸 때 코드를 건들지 않는 방법

커서를 변경시킬 경우, 예기치 않은 오류가 일어날 가능성이 매우 높음.

제한적으로 사용해야 함 : 다시 실행하거나, 건너뛰어도 실행에 문제 없는가? 확인

아무래도 쓰는 걸 권장하지는 않음

디버깅의 기초 : 싫어! 내가 직접 바꿀 거야!

Page 17: 당신의 디버깅에 니코니코니

디버깅 중, 값 변경이 필요할 때가 존재

변수 창의 값 필드 중 변경하고 싶은 값을 더블 클릭

변경 완료!

이 역시 예기치 않은 문제를 일으킬 가능성이 존재

값을 변경해도 코드에 문제가 없는지 확인

디버깅의 기초 : 싫어! 내가 직접 바꿀 거야!

Page 18: 당신의 디버깅에 니코니코니

자주 사용/변경하는 값은 변수 창에서 보는 것보다 텍스트 편집기의 코드 위에고정해서 보는 게 효율적

DataTips : 마우스 커서를 고정할 변수 위에 가만히 두면

처럼 변수와 현재 값이 간략하게 표시.

버튼을 눌러 고정하면 끝.

- 이동 가능

- 변수에 대한 메모 가능

- 디버깅 종료 후 마지막 값 저장

디버깅의 기초 : 두고두고 확인합시다.

Page 19: 당신의 디버깅에 니코니코니

배포 테스트를 위해 일반적인 방법으로 프로그램 실행 중에 버그를 발견했을 때

[디버그(D) > 프로세스에 연결(P)] 로 실행 파일과Visual Studio를 연결

※ 단, 실행 프로그램이 소스코드

와 동일한 버전이어야만 가능.

심화 : 실행중인 프로그램을 디버깅해보자!

Page 20: 당신의 디버깅에 니코니코니

코드 분석 : 컴파일러가 코드를 분석해서 문제가 있을법한 부분들을 조목조목 알림못된 것들 너무 깐깐해

프로그래머가 흑마법 기교를 부려 작성한

부분도 다 잡음.

해당 문제들 대부분을 고치는 것을 추천

[분석(N)>솔루션에서 코드 분석 실행(Y)]

심화 : 코드 분석은 하고 코딩하세요?

Page 21: 당신의 디버깅에 니코니코니

진단 도구 : Visual Studio의꽃.

진단 목적에 따라 CPU 사용량, GPU 사용 현황

메모리 사용량, 성능 마법사 등을 사용.

진단 시작 후 프로그램 실행부터 종료까지 진단, 보고서 작성에 몇 분의 시간이 소요

필요할 때 적절한 진단 도구를 이용하여 프로그램의 디버깅 시간을 효과적으로 단축

자세한 사항은 다음 링크를 참조

심화 : 진단 도구 활용해 보기.

https://msdn.microsoft.com/ko-kr/library/dd264943.aspx

Page 22: 당신의 디버깅에 니코니코니

프로파일링 보고서 예시. 실행 부하 과다 경로, 개별 작업이 가장 많은 함수 등을 표시, 언제 CPU를 가장 많이 사용하였는지 표시.

심화 : 프로파일러

Page 23: 당신의 디버깅에 니코니코니

Visual Studio 2015의 경우, 디버깅 시 자동으로 진단 시작

CPU와 메모리에 대해서 진단

프로파일러를 사용하기 위해서는

디버그(D) > 프로파일러 > 성능 탐색기(E) > 새 성능 세션

성능 탐색기 > 대상 > 대상 프로젝트 추가(P) > 프로파일링하기 위한 프로젝트 추가

프로파일링 시작

많이 호출되는 함수에서 고칠 점은 없는지 확인 할 수 있음.

심화 : 진단 도구 활용해 보기.

Page 24: 당신의 디버깅에 니코니코니

Code Level Debugging

이런 건 알고 디버깅 하시나요?

Page 25: 당신의 디버깅에 니코니코니

디버깅의 기초 : 범위 위반

범위 위반 : 할당된 영역을 벗어나 할당되지 않은 위치를 접근하려고 할 때 발생

Segment Fault : OS에서 할당한 프로그램 데이터 범위 밖으로 접근할 때 발생

둘 모두 정상적인 접근 범위 밖을 접근하려고 할 때 발생!

해결법 : 1. 접근 전 항상 정상적인 접근 범위 이내인지 확인

코드 발적화의 지름길

2. 중단점을 이용하여 범위 위반 시 프로그램 일시 중지

Page 26: 당신의 디버깅에 니코니코니

디버깅의 기초 : 범위 확인

for(size_t idx = 10; idx >= 0; --idx) { } 는 오류가 나는 구문.

왜?→ size_t는 unsigned int의 typedef형.

→ idx >= 0은 underflow로 인하여 항상 true.

→ 무한 루프 및 오류 발생!

Page 27: 당신의 디버깅에 니코니코니

디버깅의 기초 : is this nullptr?

클래스 사용 중 도저히 나올 수 없는 기괴한 값이 나올 경우가 존재

대부분 변수 확인 시 this 값이 nullptr 또는 0xcdcdcdcd 같은 값이 들어가 있음.

둘 모두 잘못된 코딩이 1차적 문제 똑바로 코딩하세요! 컴파일러불쌍해…

nullptr 은 확인이 그나마 간단. nullptr 로 초기화 해준 뒤 최초 참조 라는 뜻.

0xcdcdcdcd : 힙 영역에 올릴 데이터가 초기화도 안 해놓은 상태인데 할당해야 할 경우 Visual Studio에서 임시로 할당한 값.

+0xcccccccc : 지역 변수를 초기화하지 않고 할당할 경우 나오는 값.

→ 할당 문제. 이 문제들이 발생했다는 것은 할당이 제대로 이루어지 않아 정상적인 값이 할당되지 않았다는 것.

Page 28: 당신의 디버깅에 니코니코니

디버깅의 기초 : if는 값을 넣는다.

값 비교를 통해 if문을 사용할 때 == 와 = 을 주의하라는 건 매우 기초적.

bool 형 변수들은 그 자체로도 true와 false를 가지므로 == true 또는 == false 는불필요한 연산.

bool 형을 반환형으로 가지는 함수도 if 문 안에 넣을 수 있음.

단항 논리 연산자 중 ! 는 비트를 반대로( 1→0, 0→1) 하는 역할 bool bTrueFalse = false; if(!bTrueFalse){ /*동작*/ }

!변수명 은 파악하기 어려움 → ! 변수명 처럼 변수, 함수명과 띄어 표시.

또한, 헷갈리지 않는 코딩용 폰트로 코딩

Page 29: 당신의 디버깅에 니코니코니

유지보수하기 어렵게 코딩하기 : if의 신묘함

논리 연산 &&는 왼쪽 피연산자부터 연산, 하나라도 false 값이 나올 경우 false 값 반환.

이를 이용하여 if문을 다음과 같이 사용할 수 있음.

이 경우 어느 부분에서 false 값이 나타났는지 모름.

코드를 몇 줄 줄이다가 디버깅을 몇 시간 할 수 있음.

항상 올바르게 동작하는 코드가 아니라면 이런 방식으로 코딩하면 안 됨!

Page 30: 당신의 디버깅에 니코니코니

전처리기 : 컴파일 타임에 이미 처리된 문장. 전처리기를 이용하여 소스 코드를 여러 파일로 분할 가능(#include)

전처리기는 문장의 공백을 제외한 첫 번째 문자로 #이 위치해야 함.

전처리기는 다음 등이 있음 : #include, #define, #pragma, #ifdef, #using…

전처리기에 대한 이야기가 아니기 때문에 자세한 내용 생략 참고 자료 : https://msdn.microsoft.com/ko-kr/library/wy090hkc.aspx

이제부터 살펴볼 연산자는 #define, #if 문.

전처리기는 쓰고 코딩하세요?

Page 31: 당신의 디버깅에 니코니코니

ANSI와 호환되는 기본적으로 정의된 매크로 _ _ FILE_ _ : 현재 소스 파일의 이름을 반환

[프로젝트 속성 > C/C++ > 고급 > 전체 경로 사용] 으로 반환 값을 전체 경로로 변경 가능

_ _ LINE_ _ : 매크로를 호출한 위치를 문자열로 반환.

Visual Studio에서 기본적으로 정의해 놓은 매크로 _DEBUG : Debug로 컴파일 시 기본 정의

NDEBUG : Release로 컴파일 시 기본 정의

_ _ FUNCTION_ _ : 함수 내에서 사용 가능하며, 호출된 지역의 함수 명을 반환

기본 제공하는 매크로를 이용하여 어느 부분에서 오류가 났는지 로그 파일을작성할 수 있음

전처리기 기본 : 기본 정의 매크로

Page 32: 당신의 디버깅에 니코니코니

#define : 컴파일 타임에 정의된 위치의 모든 단어를 내용으로 변경.

단순 치환이기 때문에 오류 발생 가능성 존재

또한, 단순 치환이기 때문에 매우 간단한 함수를 대체하기도 함.

C++에서는 inline 함수가 있기 때문에 #define 함수는 지양하는 것이 좋음.

단순히 #define ~~만 해도 동작. 이 경우 #define 은 정의된 것 이외의 역할은 하지 않음.

ex)

#define MyDefine 1

#define MyDefFunc(x) (x – 10)

사용 방법

#define USE_AUDIO // 오디오 기능을 사용.

#define SET_DEBUG_LEVEL 3 // 코드에서 만들어 둔 디버그 단계 중 3단계를 사용

전처리기 기본 : #define

Page 33: 당신의 디버깅에 니코니코니

#define 은 #define 하나가 아닌 #if 문과 같이 사용하여야 효과가 증대

#if, #ifdef, #ifndef 등을 통해 컴파일 타임에서 코드 제어가 가능

#if~ 전처리기는 #else 또는 #elif로 해당 경우가 아닐 경우의 코드를 작성 가능

#if~ 전처리기는 #endif 를 사용하여 닫아야 함.

#ifdef : #define 으로 정의된 단어만 사용 가능

#elif : #else #if 와 동일한 개념. 훨씬 간편.

#else 는 #if ~~ 와 #endif 사이 단 한번만 사용 가능

전처리기 기본 : #if~~

ex)

Page 34: 당신의 디버깅에 니코니코니

#ifdef 로 생성될 프로그램에 디버깅 관련 코드를 생성하지 않게 만들 수 있음 Debug 모드로 생성한 프로그램에서는 존재하지만 Release 모드로 생성한 프로그램

에는 존재하지 않는 코드를 구현 가능 → 배포 시 코드 수정이 편리

#undef ~~: 현재 줄 부터 정의된 단어 ~~를 정의 해제함.※ 단, 프로그램 실행 흐름과 무관하게 소스 코드의 줄로만 판단.

사용처 : 디버깅이 필요하지 않은 부분에서는 디버깅을 하지 않을 수 있음.

함수에서 임시 정의를 내려 정의 해제할 정의 값을 알고 있는 상태에서

정의 해제 후 동작한 뒤 다시 정의 내리는 방법도 가능.

추가 : 토큰 붙여 넣기 연산자 별도의 토큰이 단일 토큰으로 병합되도록 허용

#define MERGETOKEN(x, y) x##y → xy 로 인식.

전처리기 활용 : #define 심화

Page 35: 당신의 디버깅에 니코니코니

#if 를 이용하여 #include 여부도 설정이 가능

디버깅을 위한 모듈을 헤더 파일에 둔 뒤 그걸 #include 하는 방식으로 코딩할 수 있음.

Release 생성 프로그램의 경량화 및 최적화에 도움

#pragma comment (lib, LIBRARYNAME) 형식으로 디버깅에 필요한 DLL을 추가 가능

#if로 Release 모드에서 추가하지 않을 수 있음.

전처리기 활용 : #if~~ 심화

ex)

+ #if문 활용 편(2)

Page 36: 당신의 디버깅에 니코니코니

중단점을 이용하여 프로그램을 일시 중지할 수 있지만 협업 시 중단점 위치에주석 등의 메모를 남기기는 애매한 부분이 존재.

중단점은 프로젝트에 종속되기 때문에 소스 코드를 Copy & Paste 할 경우 소실.

이럴 때 쓰는 방법 : assert, _DEBUG_ERROR()

중단하는 프로그래밍

Page 37: 당신의 디버깅에 니코니코니

필요한 헤더 파일 : #include <assert.h> (C++ 헤더 규칙으로는 #include <cassert>)

사용 방법 : assert(조건문);true 이면 생략, false 이면 발생.

조건문이 실패할 경우 다음과 같은 오류 창 출력

[Assertion failed : 조건문, 파일 경로, 오류 줄 수]

형태로 출력

assert는 작동하면 무조건 프로그램을 종료.

중단하는 프로그래밍 : assert

Page 38: 당신의 디버깅에 니코니코니

필요한 헤더 파일 : #include <xutility> (내장됨 : #include <iostream>)

사용 방법 : _DEBUG_ERROR();항상 실행.

조건문이 실패할 경우 다음과 같은 오류 창 출력

항상 실행하기 때문에 if문으로 조건문을 처리해야 함.

_DEBUG_ERROR()는 프로그램을 종료하지 않고 경고.

중단하는 프로그래밍 : _DEBUG_ERROR

Page 39: 당신의 디버깅에 니코니코니

Release 모드는 코드 최적화로 인하여 Debug 모드에서는 발생하지 않던 문제가 발생할 수 있음. 이 경우, Debug의 안전 장치 안에서만 정상 동작했기 때문에 좋은 코드가 아님.

Release 모드에서는 값 확인이 제대로 안 됨

중단점 찍어서 디버깅하기는 무리

정답은 이미 나옴 콘솔에 찍기

출력에 LOG로 남기기

LOG용 텍스트 파일에 LOG 남기기

문자열로 박제

Release 모드도 디버깅이 하고 싶어!

Page 40: 당신의 디버깅에 니코니코니

Windows Program의 경우 디버깅 로그를 위한 콘솔이 매우 편리할 수 있음.

AllocConsole() 함수를 이용하여 콘솔 생성 가능.freopen("CONIN$", "rb", stdin);

freopen("CONOUT$", "wb", stdout);

freopen("CONOUT$", "wb", stderr);

//cout, cin, cerr 사용을 위해서는 아래 구문을 추가

std::ios::sync_with_stdio();

프로그램 종료 시 FreeConsole() 함수를 호출하여 콘솔 종료

※Visual Studi0 2013 이후 버전에서는 오류가 발생 [프로젝트 속성 > C/C++ > 전처리기 > 전처리기 정의] 에서 _CRT_SECURE_NO_WARNINGS 를 추가.

※ cout 또는 wcout 사용 시 locale 설정을 해야 정상적으로 출력됨.

Release 모드의 디버깅 : 콘솔에 찍기

Page 41: 당신의 디버깅에 니코니코니

Windows 기반 프로그램에서는 다음 함수로 로그를 기록

OutputDebugString(str)

디버깅 중 또는 디버깅이 끝날 때 확인.

확인 방법 [디버그(D) > 창(W) > 출력(O)] 를 통해 출력 창 실행

출력 보기 선택을 ‘디버그’ 로 변경

확인

C#, JS에 대한 로그 남기는 방법은 다음 웹 사이트 참고.

Release 모드의 디버깅 : 출력 창에 로그 기록

Page 42: 당신의 디버깅에 니코니코니

전역에서 접근 가능한 파일을 생성 또는 싱글톤으로 프로젝트 내에서 접근 가능하도록 구현

해당 예제는 Debug 모드일 때에만 가능하도록 했지만

_DEBUG 를 지우면 Release 모드에서도 사용 가능

로그를 남기는 것을 원하지 않으면

#define _USE_DEBUG_OUTPUT_TEXT를 주석처리

원하는 대로 개조해서 사용

샘플 코드는 다음 링크 참고. https://gist.github.com/LusainKim/dc3eb19bc51b1322a518

Release 모드의 디버깅 : 파일에 로그 남기기

Page 43: 당신의 디버깅에 니코니코니

디버깅을 위한 문자열 선언

sprintf, wsprintf 등의 함수를 이용해

확인을 원하는 값을 문자열에 입력

문자열로 확인

Release 모드의 디버깅 : 문자열 박제

Page 44: 당신의 디버깅에 니코니코니

Thank you!

열심히 코딩하세요!

Page 45: 당신의 디버깅에 니코니코니

참고 문헌

중단점 창 : https://msdn.microsoft.com/ko-kr/library/aa290723(v=vs.71).aspx

조사식 : https://msdn.microsoft.com/ko-kr/library/4dt5w8ta.aspx

직접 실행 창 : https://msdn.microsoft.com/ko-kr/library/f177hahy.aspx

매크로 : https://msdn.microsoft.com/ko-kr/library/b0084kay.aspx

디버그 출력 : https://t.co/00absV1SnZ

당신의 프로그래밍에 디버깅 더하기 Visual C++ 디버깅 기초에서 고급까지

최홍배 著 (한빛 미디어, 2014, ISBN : 978-89-6848-658-6 15000/비매품)

Debug It! 실용주의 디버깅폴 부처 著, 박일 譯 (에이콘, 2010, ISBN : 978-89-6077-1413)

유지보수하기 어렵게 코딩하기(모방을 방지하기 위하여 이하 생략)