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