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;
}


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