소프트웨어/C# & ASP.NET

C#의 디버깅과 오류 처리

falconer 2008. 7. 24. 09:13
* 의미적 오류(semantic error) 또는 논리적 오류(logic error)
  : 실행 자체에는 문제를 일으키지 않지만 응용 프로그램의 논리에는 해를 입히는 오류.
* 디버깅(Debugging)
  : 오류가 보고되었으면 언제 어떤 문제가 어떻게 일어나는지를 파악하고 원일을 해결하는 작업.
1. Visual Studio 에서의 디버깅
   1) 프로그램이 디버그 모드 하에서 실행되면, 사람이 작성한 코드 이상의 것이 내부적으로 진행된다. 디버그 필드는 응용 프로그램에 대한 심볼 정보를 유지하며, VS는 그러한 정보를 통해서 코드의 실행을 구체적으로 알아낸다.  
   2) 심볼 정보로 가능한 작업들 (프로젝트 컴파일한 후 Debug 디렉토리의 .pdb 파일에 저장된다.)
      (1) 디버깅 정보를 VS로 출력
      (2) 응용 프로그램 실행 도중에 현재 범위 안의 변수들의 값을 조사, 수정
      (3) 프로그램의 실행을 일시 정지했다가 다시 시작
      (4) 코드의 특정 지점에서 실행을 자동적으로 정지
      (5) 프로그램의 실행을 한 번에 한 줄씩 진행
      (6) 응용 프로그램 실행 도중 변수 값의 변화를 감시
      (7) 함수에 대한 테스트 호출을 수행
2. 비 중단 모드(정상 모드)에서의 디버깅
   1) 응용 프로그램 실행 도중 중요한 지점들에서 디버깅 정보를 출력해두고 나중에 그것을 분석 한다.
   2) 출력 창은 VS 개발 환경 아래쪽의 [작업 목록] 창과 같은 공간을 공유한다. 출력 창에는
     코드의 컴파일과 관한 정보가 출력되며, 컴파일 도중 생긴 오류 등도 이곳에 출력된다.
3. 디버깅 정보의 출력
   1) 런타임(실행 시점)에서 출력 창에 텍스트를 출력하는 것은 매우 간단한 일이다. 그냥
      Console.WriteLine() 대신 다음 두 명령들 중 하나를 사용하면 된다.
      (1) Debug.WriteLine()
           : 디버그 빌드에서만 작동하며, 릴리즈 빌드에서는 아예 컴파일되지 않고 완전히 무시된다.
      (2) Trace.WriteLine()
           : 오직 릴리즈 모드에서만 작동한다.
      ※ 디버그 버전은 모든 종류의 추가적인 분석 정보를 표시하는 반면, 릴리즈 버전은 사용자가 꼭 알아야 할만한 정보만 출력한다.
      (3) Debug.Write()
           : Debug.WriteLine() 함수와 동일한 구문을 사용하나, 출력 끝에서 줄을 바꾸지 않는다.
      (4) Trace.Write()
           : Trace.WriteLine() 함수와 동일한 구문을 사용하나, 출력 끝에서 줄을 바꾸지 않는다.
   2) 그 외에 다른 명령어들
      (1) Debug.WriteLineIf()
      (2) Trace.WriteLineIf()
      (3) Debug.WriteIf()
      (4) Trace.WriteIf()
      ※ 이들은 -If가 붙지 않는 함수들의 두 매개변수들을 가지며, 추가호 하나의 Boolean 매개변수도 가진다.(생략 불가). 이들은 Boolean 매개변수가 참일 때에만 메시지를 출력한다. 따라서 조건에 따라 디버깅 정보를 출력 창에 출력하는 것이 가능하다.
4. 중단 모드에서의 디버깅
   1) 중단 모드란 프로그램의 실행이 일시적으로 정지된 상태를 말한다.
   2) 중단 모드로의 진입
       (1) 응용 프로그램 실행 도중 VS의 아래 해당 버튼을 클릭한다.
            ▣ 모두 중단 : 응용 프로그램을 일시 정지하고 중단 모드로 들어간다.
            ▣ 중지 : 응용 프로그램을 완전히 끝낸다.
            ▣ 다시 시작 : 응용 프로그램을 다시 시작한다.
       (2) 중단 모드로 진입하는 가장 기본적인 방법이나, 단점은 중단 시점을 정밀하게 제어하기 힘들다는 것이다.
   3) 중단점
       (1) 중단 지점을 명시적으로 정의하고자 소스 코드에 표시하는 것으로, 실행이 자동적으로
           중단 모드에 진입하게 만드는 역할을 한다.
       (2) 중단점이 작용하는 방식
            ▣ 중단점에 도달하면 즉시 중단 모드로 진입한다.     
            ▣ 중단점에 도달했을 때, 주어진 부울 표현식이 true이면 중단 모드로 진입한다.
            ▣ 중단점에 일정 횟수 이상 도달했을 때에만 중단 모드로 진입한다.
            ▣ 중단점에 도달했을 때, 이전에 도달한 이후로 변수의 값이 변했으면 중단 모드로 진입한다.
       (3) 중단점은 오직 디버그 빌드에서만 사용할 있다. 릴리즈 모드의 경우에는 모든 중단점이 무시된다.
       (4) 중단점을 소스 코드에 추가하는 방법
            : 중단점에 도달했을 때 무조건 즉시 중단모드로 진입하게 되는 단순한 중단점이라면,
             소스 코드 줄 왼쪽의 회색 영역을 왼쪽클릭하거나, 또는 줄 자체를 오른쪽 클릭하고
             [중단점 삽입]을 선택하면 된다. 그러면 코드 줄이 선택되면서 왼쪽에 빨간 원이 나타
             나는데, 그것이 바로 중단점이다.
       (5) 소스 코드의 모든 중단점들에 대한 정보는 [중단점] 창에서 볼 수 있다. 이 창은 [디버깅] 창에서 [중단점]을 선택하면 화면 아래에서 볼 수 있다. 여기서는 중단점을 해제, 삭제 또는 중단점의 속성을 변경할 수 있다.
       (6) 중단점 창에서 속성에는 [함수],[파일],[주소]라는 세 가지 탭들로 구성되어 있는데, 이 탭들을 통해서 중단점의 위치를 변경할 수 있다. 그리고 [조건]과 [적중 횟수]라는 속성들이 표시되는데, [조건]은 임의의 부울 표현식을 [적중 횟수]는 중단점에 몇 번 도달했 을 때 중단 모드로 진입하게 할 것인지를 설정할 수 있다.
   4) 또 다른 중단 모드 진입 방법
       (1) 처리되지 않은 예외가 던져질 때.
       (2) 어설션(assertion)이 발생했을 때.
           ▣ 어설션은 응용 프로그램의 실행을 중단하고 사용자 정의 메시지를 출력하는 명령이다.
           ▣ 어설션은 종종 개발 과정 도중에 응용 프로그램이 의도한 대로 실행되고 있는지를 시험하기 위한 수단으로 쓰인다.
           ▣ 디버그 버전인 Debug.Assert() 함수와 릴리즈 버전인 Trace.Assert() 함수가 있으며, 디버그 버전은 디버그 빌드에서만 컴파일된다. 이 함수들은 세 개의 매개변수가 있는데, 첫번째는 하나의 부울 값으로 그 값이 false이면 어설션이 발생한다. 두번째와 세번째는 팝업 대화상자와 출력 창에 표시될 메시지들이다.
5. 변수 내용의 감시
   1) 변수의 값은 중단 모드에서 소스 코드 안의 변수 이름에 마우스를 올려놓으면 확인할 수 있다. 또한 표현식 전체를 선택하고 마우스를 올려 놓으면 표현식의 결과를 볼 수 있다. 그러나 이 방법은 좀  제한적이며, 예를 들어서 배열의 내용은 볼 수가 없다.
   2) 디버깅의 중단 모드의 경우 새로운 창에서 다음과 같은 세 가지 탭들이 있다.
      (1) [자동] - 현재와 이전 문장에서 쓰이는 변수들이 나타난다.
      (2) [지역] - 현재 범위 안의 모든 변수들이 나타난다.
      (3) [조사식 N] - 커스텀 가능한 변수들과 표현식들이 나타난다(N은 1에서 4)
      ※ 소스 코드 창에서 변수를 조사식 창에 끌어놓은 식으로 변수를 추가할 수도 있다.
      ※  원하는 변수를 오른쪽 클릭한 후 [간략한 조사식] 을 선택해서 사용할 수도 있다.
   3) 중단 모드 안에서 단계적으로 실행
      (1) 한 단계씩 코드 실행 - 현재 문장을 실행하고 다음 문장에서 멈춘다.
      (2) 프로시저 단위 실행 - 위와 같으나, 내포된 코드 블럭으로는 들어가지 않는다.
      (3) 프로시저 나가기 - 코드 블럭의 끝까지 실행하고, 그 다음 문장에서 멈춘다.
   4) 명령창에는 [명령]과 [직접 실행] 모드가 있다.
      (1) 명령 모드에서는 메뉴 줄이나 버튼 등을 사용하지 않고 VS의 특정 기능을 실행시킬 수
          있다. 실행모드에서는 실행될 실제 코드 줄들 사이에서 임의의 C# 코드를 직접 실행해
          볼 수 있다.
      (2) 명령모드에서는 창의 각 줄에 > 표시가 나타난다. 명령 모드에서 직접 실행 모드로 바꾸려면 그 창에서 "immed"를 입력한 후 엔터를 치면 되고, 다시 명령 모드로 돌아가려면 ">cmd"를 입력하고 엔터를 치면 된다.
   5) 호출 스택 창은 작업 목록이나 출력 창과 같은 공간을 사용하는 또 하나의 창이다.
      (1) 호출 스택은 현재 중단된 위치에 도달한 경로를 알려주는 역할을 한다.
      (2) 오류가 처음 발생했을 때 그 오류 바로 이전에 어떤 일이 일어났는지를 쉽게 추적할 수
          있다.
6. 오류 처리
   1) 예외(exception)은 실행 도중 또는 코드가 호출한 함수 안에서 발생한 오류를 가리킨다.
   2) try...catch...finally
      (1) C# 언어에는 구조적 예외 처리(Structured Exception Handling, SEH)를 위한 구문이
          포함되어 있다. try, catch, finally는 각각 개별적인 코드 블럭을 동반하며, 반드시 순서
          대로 써줘야 한다.
      (2) 기본 구조
           try
           {
               ....
            } 
            catch (<예외형식> e)
            {
               ...
             }
            finally
            {         
               ...
             }
      (3) catch 블럭 없이 하나의 try와 하나의 finally만 존재하는 구조나, 하나의 try에 여러 개의 catch 절들이 들어 있는 구조도 가능하다. catch가 존재하면 finally는 생략할 수 있으나, catch가 없으면 반드시 finally가 존재해야 한다.
      (4) try - 예외를 던질 코드를 감싼다. 여기서 "던진다(throw)"라는 말은 예외를 발생시킨다는 뜻이다.
      (5) catch - 예외가 던져졌을 때 실행될 코드를 감싼다. <예외형식>을 통해서 형식을 지정해야 하며, <예외형식>을 생략하면 모든 종류의 예외들에 반응하게 된다.
      (6) finally- 예외가 던져졌든 그렇지 않든 항상 실행될 코드를 감싼다. finally 코드의 블럭은 예외가 던져지지 않았을 때, 예외가 던져지고 catch에 의해 처리되었을 때, 또는 예외가 처리되지 않아서 응용 프로그램이 종료되어야 할 때 모두 반드시 실행된다. 따라서 여기에는 조건에 상관없이 반드시 실행되어야 하는 코드를 넣는다.
   3) 예외의 나열과 설정
      (1) 예외창 ([디버그 | 예외] 선택 또는 Ctrl+Alt+E) 에는 모든 예외들이 범주별로, 그리고
          .NET 라이브러리 네임스페이스별로 나열된다.
      (2) 창 아래의 라디오 버튼들을 이용해서 발생 또는 처리 방식을 바꿀 수 있다. 기본적으로
          [부모 설정 사용]으로 되어 있는데, 이는 자신이 속한 범주의 설정을 따른다는 것이다
      (3) 옵션중 [중단하고 디버거 실행]은 예외가 던져졌을 때 예외가 처리되기 전에 디버거가
          뜨며, [계속]은 예외를 아예 처리하지 않고 진행하는 것이다.
   4) 예외 처리에서 주의할 점
      (1) catch 블럭은 반드시 범용적인 catch 블럭 전에 나와야 한다. 이를 어기면 컴파일이 실패한다.
      (2) catch 블럭 안에서 예외를 던지는 것도 가능하다. 특정 형식의 예제를 던질 수도 있고,
          throw만 써줄 수도 있다.
          throw;     // catch블럭이 처리한 예외가 다시 던져진다.


출처 : http://blog.naver.com/web28?Redirect=Log&logNo=60010716771