您的位置:首页 > 其它

(Visual Studio)Part 4: Setting up Code for the Debugger

2015-01-05 16:08 549 查看

In the fourth part of the series on debugging in Visual Studio, we will discuss how to set up your code for the debugger.

Debug break

A direct call to a debug break can be used to stop the execution of a program. Why is this different than a breakpoint and why would you use it? Generally you would use it if you are not going to launch the debug session from Visual Studio, you are going
to launch it after the fact. So if we want to try this how is a debug break called in c

Calling
__debugbreak() can be used to generate a software breakpoint. This function is designed to be portable between platforms. You could also use the Win32 version DebugBreak() but it is not portable. So once you call

__debugbreak() what happens from there? An exception is thrown and your program stops execution. This gives the programmer the opportunity to use Visual Studio to 'attach' to the process that is running the executable.

To attach to a running process and use the Visual Studio debugger, go to Tools and then select 'Attach to Process'. If you're running locally there is no need to change any of the dialog settings. However, if you are trying to run a debugger session remotely,
you will need to change the Transport to Remote, and then the Qualifier to the remote PC you are trying to reach. Either way, once you have the process list simply find the process that you want Visual Studio to attach to and click OK. Visual Studio will then
attach to this process and your debug session will begin.

A practical example of using
__debugbreak() would be to debug a service. You cannot launch a service directly from Visual Studio; it must be launched with the Service Control Manager. So there is no way to directly debug it from the IDE. You must 'attach' to the process in order to
debug it. The problem with debugging a service using this method is that you cannot debug the service from launch; it will simply launch and begin its run state.

Assertions

An assertion in code is a test of a condition and if the condition fails the execution of the program halts. It is designed to only be when the program is complied as debug. When an
assert() is called it is accompanied by a message indicating which expression failed, the line number and module where the assertion took place. In a Windows application the
assertion will come in a message box. In a console application it will go to the console screen.

In the following example, you can see that the string is tested for NULL. If the char array being passed in is NULL, without the assert in the debug build the memory doesn't exist and an exception would be thrown. Instead, the assert would fail and tell
the programmer that something went wrong with this function.

void TestFunc(char *pszName)
{
assert(pszName==NULL);
strcpy(pszName,"Tom Smith");
}

The assert macros
_ASSERT, _ASSERTE are used during debugging and are only available if the _DEBUG macro is defined.
_ASSERTE is used to properly print out any Unicode characters that are in the expression passed to the macro. When either of these assert, that amounts to the report that the
assertion failed, it lists the condition that failed and the source code module and line number it failed on. By default, in a Windows application the assertion will come in a message box and in a console application it will go to the console screen.

#define _DEBUG
void TestFunc(char *pszName)
{
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

_ASSERT(pszName==NULL);
strcpy(pszName,"Tom Smith");
}

It may appear on the surface that
assert() and
_ASSERT, _ASSERTE do the same thing. As far as behavior of halting execution on a failed Boolean condition they do. However the macros are only called when _DEBUG macro is defined. The other difference is that you can define the desired behavior of the
assert through a series of calls to
_CrtSetReportMode(). This is because the macros invoke a
_CrtDbgReportW report message and this mechanism is designed to allow a programmer to track progress of a debug build. You can define the macro assert to report to a debug file, to only use the console window instead of a message box, etc.

Exception Handling

Exception handling is essentially a way for the programmer to do error handling on parts of code that may fail under certain conditions without halting the program. For example, if a character array is access without having its memory defined it would normally
throw a first chance exception and the operating system would halt the program. With exception handling this is caught and can be handled by the programmer.

Here is an example of exception handling in code. Assume that the *pszName character array passed into this function is NULL. You can see from this example that the program doesn't actually halt, what happens is when the strcpy call is 'tried', the exception
is thrown by the operating system but is 'caught' by the catch block. So instead of halting the program, the program reports the error and returns FALSE instead of TRUE from this function. The syntax catch(.) means that ANY exception will be caught and handled.

BOOL TestFunc(char *pszName)
{
try
{
strcpy(pszName,"Tom Smith");
}
catch(.)
{
printf("ERROR: Cannot copy string into pszName!\n");
return FALSE;
}

return TRUE;
}

void main()
{
char *pszMyName = NULL;

if(TestFunc(pszMyName)==FALSE)
{
printf("ERROR: Forgot to instantiate array, aborting");
exit(-1);
}

exit(0);
}

Catching any exception is ok for very quick generic stuff but is not all that useful in tracking what the specific issue might be. How do we narrow down the exception handling to specific items? This is easily handled by using a throw and defining the specific
exception in the catch block we need. Here the exception of char * is the only thing that will be checked for an exception. When the check for NULL is made on the variable and we force the exception with the throw call, we can tell the exception handler exactly
what caused the problem.

BOOL TestFunc(char *pszName)
{
try
{
if(pszName == NULL)
{
throw "ERROR: pszName parameter was NULL!";
}
strcpy(pszName,"Tom Smith");
}
catch(char * error)
{
printf("ERROR: %s, pszName == NULL, cannot copy name into array\n",error);
return FALSE;
}

return TRUE;
}

void main()
{
char *pszMyName = NULL;

if(TestFunc(pszMyName)==FALSE)
{
printf("ERROR: Forgot to instantiate array, aborting");
exit(-1);
}

exit(0);
}

The items that are put into the catch function are not limited to just variable types. A class can be passed that is used to hold exception data. Below is an example of this type of class exception. You can see that there are now two types of exceptions
that are throw using the class, we pass the enumeration into the constructor in order for the class to track what the exception is.

enum ExceptionErrors
{
ArrayIsNull=1,
ArrayNotBigEnough
};

class CMyException
{
int m_iErrorCode;

public:
void ShowDescription()
{
if(m_iErrorCode & ArrayIsNull)
{
printf("ERROR: Array variable was NULL\n");
}

if(m_iErrorCode & ArrayNotBigEnough)
{
printf("ERROR: Array size to small\n");
}
}

a99b
CMyException(int iError){m_iErrorCode = iError;}
};

BOOL TestFunc(char *pszName, int iNameLength)
{
try
{
if(pszName == NULL)
{
throw CMyException(ArrayIsNull);
}

if(iNameLength

Miscellaneous Debugging Calls

There are other calls that can be made to perform some types of debugging. The reasons to use these types vary but generally these are all called to halt execution of a running program due to some error condition.

abort - Halts the current program whenever this line is called
raise - Halts the program with a specific error, abnormal termination, floating point error, illegal instruction, CTRL+C interrupt, illegal storage access and a request to terminate.
signal - This is similar in concept to raise with the difference being you must define your own error handler. The general idea is you raise the normal signal and then perform post process error handling.
Original website: http://www.cprogramming.com/tutorial/visual_studio_debugging_code_setup.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: