A place where programmers can discuss various programming topics and experiences.



Exception Handling Warnings in Visual Studio

Have you ever seen this cryptic little C++ compiler warning before in Visual Studio 7.x (.NET 2003)?

cl: Command line warning D4025: overriding '/EHs' with '/EHa'

I've seen it a number of times but always ignored it because other articles have said that "the compiler knows better." Well, the compiler might know better but I want to know why it knows better. So let's dissect this warning.

In Visual Studio, you can specify the Exception Handling model in the Code Generation property page of a C++ project. What you are selecting is whether or not the compiler uses an asynchronous exception model or a synchronous exception model. The asynchronous model is an older exception handling mechanism where the compiler assumes any instruction can generate an exception (hardware). This significantly increases the overall code size because the compiler must have mechanics for tracking the lifetime of objects that cannot unwind. The synchronous model is new and tells the compiler that exceptions can only be thrown with a throw statement. Because the compiler can now assume that exceptions will only be thrown by a throw statement or at a function call, all that extra object lifetime tracking code is not supplied by the compiler. The MSDN states that hardware exceptions can still be caught using the synchronous model, "... However, some of the unwindable objects in the function where the exception occurs may not get unwound, if the compiler judges their lifetime tracking mechanics to be unnecessary for the synchronous model."

So how in the world did you get the aforementioned compiler warning in the first place? There are a couple of things to look for.

Note: Structured exception translators (for the uninitiated) are used so that C exceptions (raised always as of type unsigned int as opposed to C++ exceptions which can be raised of any type) can be handled by a C exception wrapper class and therefore attributed a type. This allows a matching C++ catch handler to catch a C exception. If you have C code mixed in your C++ project that uses structured exception translators, you will have to use the asynchronous exception model or the compiler will throw the above warning.

In VS 7.x, it has been documented that the inability to select the asynchronous exception model ('/EHa') in the project properties dialog was a bug. To get around this in 7.x, you need to select "No" for the "Enable C++ Exceptions" property. Then go to the "Command Line" property and add "/EHa" in the "Additional options" section. This will allow you to enable C++ exceptions in your projects. Here's a screenshot of the VS 2003 .NET C++ Code Generation properties dialog. This bug was fixed in version 8 and you can now select "Yes" to the "Enable C++ Exceptions" property with a value of "Yes With SEH Exceptions (/EHa)." Here's a screenshot of the updated dialog.

For my particular project, I had some C code that used structured exception translators. So that was the reason for my warning. Therefore, I disabled the option above, and added "/EHa" as an additional command line property option. In general, enabling C++ exceptions in your VS projects should always be considered thoroughly (required in my opinion) and you should never disregard warnings like this one (as I did). For this particular case, the compiler was smart enough to fix the setting at build time, but that is not always the case. Know and understand your project settings and fix all warnings if possible. Until next time...

- Gilemonster

Labels:

posted by Gilemonster @ 11:08 PM, , links to this post




Quick Observation on STL string Comparisons

I was looking through some code this week and I noticed a few lines of code that caught my eye. The lines of code were doing basic STL string comparison using the non-member overloaded operator== function. I remembered that the STL also provides an overloaded set of compare functions for strings and wondered why you would use the overloaded operator functions instead of compare. I did a bit of reading and found that there are reasons for using one over the other.

The easiest of the comparison mechanisms is obviously to use operator==. You can use it to compare string objects, string literals that are quoted, and traditional C-style string pointers. The nice thing is that it (and other operator routines) doesn't have to create temporary string objects. Here's a simple example:

#include <string>
using namespace std;

std::wstring strFirstName = L"Billy";

if (L"Billy" == strFirstName)
{
    // Do something
}
else if (L"BILLY" == strFirstName)
{
    // Do something else
}
else if (L"BillyBoy" == strFirstName)
{
    // Do something else
}

The above sample shows the simplicity of using operator==. It also should show that its use should be limited to comparing simple character sets or single characters. A value of true will only be returned when the two character sets being compared match identically with respect to length and ASCII character code (meaning "A" != "a").

The compare routines provide a mechanism for performing lexical comparisons and other more precise string comparisons. Instead of returning true or false, three values are returned.

  • 0: the operand string is lexically equal to the parameter string.
  • 1: the operand string is greater than the parameter string.
  • -1: the operand string is less than the parameter string.

You can also use the other overloaded compare routines to further specify what your lexical queries compare. Here are some examples.

#include <string>
using namespace std;

wstring strOperand = L"Billy Bob",
        strParameter = L"Billy Bob's Barbecue";

// Standard use of compare
int intComparisonVal = strOperand.compare(strParameter);

// Further specification examples
size_type iOperandStartIndex = 0,
          iNumOperandCharsToCompare = 5;

// The second example specifies the starting index of the operand
// string and how many characters in the operand string to compare.  
// So you can compare part of the operand string with the parameter
// string.
intComparisonVal = strOperand.compare(iOperandStartIndex,
                                      iNumOperandCharsToCompare,
                                      strParameter);

// The third example goes further by also specifying the starting 
// index of the parameter string and how many characters to compare 
// in the parameter string.  So you can specify part of the operand
// string with part of the parameter string.
size_type iParamStartIndex = 0,
          iNumParamCharsToCompare = 5;
intComparisonVal = strOperand.compare(iOperandStartIndex,
                                      iNumOperandCharsToCompare,
                                      strParameter,
                                      iParamStartIndex,
                                      iNumParamCharsToCompare);

// My last example shows how to compare the operand string against
// a standard C-style string.
const wchar_t * strParameterCStyle = L"Billy Bob's Barbecue";
intComparisonVal = strOperand.compare(strParameterCStyle);

There are other examples that further demonstrate the remaining overloaded compare routines which I have left out for simplicity. And you can see that they give you the ability to lexically compare STL strings and C-style strings with greater precision than using the non-member operator==. But, when do you choose one over the other and what are the details? Here's what I have learned as a set of general guidelines concerning STL string comparisons:

  • When doing simple string comparisons where you want to exclude any unneeded overhead, use the operator routines. They first compare the operand and parameter string lengths and only if they are equal does it do a character by character ASCII value code comparison.
  • When you need more precise comparisons, use the compare routines as desired. You can compare substrings which is more useful than an "all or nothing" string comparison where applicable.

So, after reading all this mess I went back and examined the code mentioned at the beginning of this article. The code was written correctly and the string comparison was being used correctly. Anyway, I thought this was a quick and simple topic. Until next time...

- Gilemonster

Labels:

posted by Gilemonster @ 1:18 PM, , links to this post