VS2008调试技术

来源:互联网 发布:姚明职业生涯平均数据 编辑:程序博客网 时间:2024/06/14 10:21

<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 nameclass 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 operatorprivate:  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 constructorName::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}// ConstructorName::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 namechar* 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 namesize_t Name::getNameLength() const{#ifdef FUNCTION_TRACE  // Trace function calls  cout << "\nName::getNameLength() called.";#endif  return strlen(pFirstname)+strlen(pSurname)+1;}// Less than operatorbool 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 operatorbool Name::operator>(const Name& name) const{  return name < *this;}// Equal to operatorbool 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 namesvoid 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];elsesecond = 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 storechar* 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 namesinit(names, arraysize);// Try out comparisonschar* phrase = 0; // Stores a comparison phrasechar* iName = 0; // Stores a complete namechar* jName = 0; // Stores a complete namefor(int i = 0; i < arraysize ; i++) // Compare each element{iName = new char[names[i].getNameLength()+1]; // Array to hold first namefor(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 namecout << endl << names[i].getName(iName) << "is" << phrase<< names[j].getName(jName);//delete jName;}delete iName;}cout << endl;return 0;}

0 0
原创粉丝点击