VS2008調試技術

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1. 通過預編譯指令和宏_DEBUG NDEBUG #ifdef #ifndef #endif等添加自己的調試代碼</span>

2.使用<assert>斷言功能定位bugs

3.使用VS2008斷電設置的高級功能,設定中斷的位置,條件(表達式的值,到達次數)等,使用自動,監視,局部變量等監視窗口跟蹤當前變量的值

4.當程序提示you have an unhandled exception,可以break定位到異常(通常爲內存錯誤)發生的位置。此時最該懷疑的是指針的錯誤使用。

此時調用堆棧(Call stack)中存儲着已經被調用,尚未完成的函數調用序列

5.調試動態內存

 內存泄露是非常嚴重的程序故障,VS提供了檢測內存泄露的函數庫<crtdbg>,其中的函數是利用定義在_CrtMemState類型中的數據結構檢查free store的。

typedef struct _CrtMemState
{
struct _CrtMemBlockHeader* pBlockHeader; // Ptr to most recently allocated block
unsigned long lCounts[_MAX_BLOCKS]; // Counter for each type of block
unsigned long lSizes[_MAX_BLOCKS];// Total bytes allocated in each block type
unsigned long lHighWaterCount; // The most bytes allocated at a time up to now
unsigned long lTotalCount; // The total bytes allocated at present
} _CrtMemState;

該有文件中包含一些有用的函數:

void _CrtMemCheckpoint(_CrtMemState* state);

int _CrtMemDifference(_CrtMemState* stateDiff,
const _CrtMemState* oldState,
const _CrtMemState* newState);

void _CrtMemDumpStatistics(const _CrtMemState* state);

int _CrtDumpMemoryLeaks();

通過標誌  _crtDbgFlag(int類型),控制自由存儲的調試操作, 這個標誌包括五個分離的控制位,包括一個使能自動內存泄露的標誌位


a._CRTDBG_ALLOC_MEM_DF When this bit is on, it turns on debug allocation so the free store state can be tracked.
b._CRTDBG_DELAY_FREE_MEM_DF When this is on, it prevents memory from being freed by delete, so that you can determine what happens under low-memory conditions.
c._CRTDBG_CHECK_ALWAYS_DF When this is on, it causes the _CrtCheckMemory() function to be called automatically at every new and delete operation.This function verifies the integrity of the free store, checking, for example, that blocks have not been overwritten by storing values beyond the range of an array. A report is output if any defect is discovered. This slows execution but catches errors quickly.
d._CRTDBG_CHECK_CRT_DF When this is on, the memory used internally by the run-time library is tracked in debug operations.
e._CRTDBG_LEAK_CHECK_DF Causes leak checking to be performed at program exit by automatically calling _CrtDumpMemoryLeaks(). You only
get output from this if your program has failed to free all the memory that it allocated.


通過函數設置標誌位:int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Get current flag

_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);


調試信息的輸出一般在debug message window 而不是輸出流,如果需要改變輸出位置,需要通過兩個函數:

(1)int _CrtSetReportMode(int reportType, int reportMode);

reportType:

  a._CRT_WARN Warning messages of various kinds. The output when a memory leak is detected is a warning.
b._CRT_ERROR Catastrophic errors that report unrecoverable problems.
c._CRT_ASSERT Output from assertions

reportMode:

a._CRTDBG_MODE_DEBUG This is the default mode, which sends output to a debugstring that you see in the Debug window when runningunder control of the debugger.
b._CRTDBG_MODE_FILE Output is to be directed to an output stream.

c._CRTDBG_MODE_WNDW Output is presented in a message box.
d._CRTDBG_REPORT_MODE If you specify this, the _CrtSetReportMode() function justreturns the current report mode.

  (2)_HFILE _CrtSetReportFile(int reportType, _HFILE reportFile);

//You set the destination for each output type with a separate call of the _CrtSetReportMode() function.

示例代碼如下:

// DebugStuff.h - Debugging control
#pragma once

#ifdef _DEBUG

//#define CONSTRUCTOR_TRACE         // Output constructor call trace
//#define FUNCTION_TRACE            // Trace function calls

#endif
// Name.h ?Definition of the Name class
#pragma once
#include <string>
#include "stddef.h"
using namespace std;
// Class defining a person's name
class Name
{
public:
  Name();                                        // Default constructor
  Name(const char* pFirst, const char* pSecond); // Constructor
  Name(const Name& rName);                       // Copy constructor

  ~Name();                                       // Destructor

  char* getName(char* pName) const;              // Get the complete name
  size_t getNameLength() const;                  // Get the complete name length

  // Comparison operators for names    
   bool operator<(const Name& name) const;
   bool operator==(const Name& name) const;
   bool operator>(const Name& name) const;

   Name& operator=(const Name& rName);                 // Assignment operator
private:
  char* pFirstname;
  char* pSurname;
};
// Name.cpp ?Implementation of the Name class
#include "Name.h"                                // Name class definitions
#include "DebugStuff.h"                          // Debugging code control
#include <cstring>                               // For C-style string functions
#include <cassert>                               // For assertions
#include <iostream>
using namespace std;

// Default constructor
Name::Name()
{
#ifdef CONSTRUCTOR_TRACE
  // Trace constructor calls
  cout << "\nDefault Name constructor called.";
#endif

  // Allocate array of 1 for empty strings
  pFirstname = new char[1];
  pSurname = new char[1];

  pFirstname[0] = pSurname[0] = '\0';           // Store null character
}

// Constructor
Name::Name(const char* pFirst, const char* pSecond)
{
  // Verify that arguments are not null
  assert(pFirst != 0);
  assert(pSecond != 0);

#ifdef CONSTRUCTOR_TRACE
  // Trace constructor calls
  cout << "\nName constructor called.";
#endif
  pFirstname = new char[strlen(pFirst)+1];
  strcpy(pFirstname, pFirst);
  pSurname = new char[strlen(pSecond)+1];
  strcpy(pSurname, pSecond);
}


// Return a complete name as a string containing first name, space, surname
// The argument must be the address of a char array sufficient to hold the name
char* Name::getName(char* pName) const
{
  assert(pName != 0);                                 // Verify non-null argument

#ifdef FUNCTION_TRACE
  // Trace function calls
  cout << "\nName::getName() called.";
#endif

  strcpy(pName, pFirstname);                          // copy first name
  strcat(pName, " ");                  // Append a space
  return strcat(pName, pSurname);      // Append second name and return total
} 

// Returns the total length of a name
size_t Name::getNameLength() const
{
#ifdef FUNCTION_TRACE
  // Trace function calls
  cout << "\nName::getNameLength() called.";
#endif
  return strlen(pFirstname)+strlen(pSurname)+1;
}

// Less than operator
bool Name::operator<(const Name& name) const
{
  int result = strcmp(pSurname, name.pSurname);
  if(result < 0)
    return true;
  if(result == 0 && strcmp(pFirstname, name.pFirstname) < 0)
    return true;
  else
    return false;
}

// Greater than operator
bool Name::operator>(const Name& name) const
{
  return name < *this;
}

// Equal to operator
bool Name::operator==(const Name& name) const
{
  if(strcmp(pSurname, name.pSurname) == 0 &&
                                         strcmp(pFirstname, name.pFirstname) == 0)
    return true;
  else
    return false;
}

Name:: Name(const Name& rName)
{
  pFirstname = new char[strlen(rName.pFirstname)+1]; // Allocate space for 1st name
  strcpy(pFirstname, rName.pFirstname);              // and copy it.
  pSurname = new char[strlen(rName.pSurname)+1];     // Same for the surname...
  strcpy(pSurname, rName.pSurname);
}

Name::~Name()
{
  delete[] pFirstname;
  delete[] pSurname;
}

Name& Name::operator=(const Name& rName)
{
  if(this == &rName)                                 // If lhs equals rhs
    return *this;                                    // just return the object

  delete[] pFirstname;
  pFirstname = new char[strlen(rName.pFirstname)+1]; // Allocate space for 1st name
  strcpy(pFirstname, rName.pFirstname);              // and copy it.
  delete[] pSurname;
  pSurname = new char[strlen(rName.pSurname)+1];     // Same for the surname...
  strcpy(pSurname, rName.pSurname);
  return *this;
}
// Ex11_02.cpp : Extending the test operation


#include <iostream>
#include <crtdbg.h>
#include <stdio.h>
using namespace std;
#include "Name.h"

// Function to initialize an array of random names
void init(Name* names, int count)
{
	char* firstnames[] = { "Charles", "Mary", "Arthur", "Emily", "John"};
	int firstsize = sizeof (firstnames) / sizeof(firstnames[0]);
	char* secondnames[] = { "Dickens", "Shelley", "Miller", "Bronte", "Steinbeck"};
	int secondsize = sizeof (secondnames)/sizeof(secondnames[0]);
	char* first = firstnames[0];
	char* second = secondnames[0];

	for(int i = 0 ; i<count ; i++)
	{
		if(i%2)
			first = firstnames[i%firstsize];
		else
			second = secondnames[i%secondsize];

		names[i] = Name(first, second);
	}
}

int main(int argc, char* argv[])
{
	// Turn on free store debugging and leak-checking bits
	_CrtSetDbgFlag( _CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF );

	// Direct warnings to stdout
	_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
	_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
	
	Name myName("Ivor", "Horton");                 // Try a single object

	// Retrieve and store the name in a local char array  
	char theName[12];
	cout << "\nThe name is " << myName.getName(theName);

	// Store the name in an array in the free store
	char* pName = new char[ myName.getNameLength() +1 ]; 
	cout << "\nThe name is " << myName.getName(pName);
	delete pName;

	const int arraysize = 5;
	Name names[arraysize];                      // Try an array

	// Initialize names
	init(names, arraysize);
	// Try out comparisons
	char* phrase = 0; // Stores a comparison phrase
	char* iName = 0; // Stores a complete name
	char* jName = 0; // Stores a complete name
	for(int i = 0; i < arraysize ; i++) // Compare each element
	{
		iName = new char[names[i].getNameLength()+1]; // Array to hold first name
		for(int j = i+1 ; j<arraysize ; j++) // with all the others
		{
			if(names[i] < names[j])
				phrase = "less than ";
			else if(names[i] > names[j])
				phrase = "greater than ";
			else if(names[i] == names[j]) // Superfluous - but it calls operator==()
				phrase = "equal to ";

			jName = new char[names[j].getNameLength()+1]; // Array to hold second name
			cout << endl << names[i].getName(iName) << "is" << phrase
				<< names[j].getName(jName);
			//delete jName;
		}
		delete iName;
	}
	cout << endl;
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章