Porting Visual C++ Code to Visual Studio 2005-2 : Page 2
by Danny Kalev
Aug 11, 2005
Page 2 of 3
Code Review and Analysis
Earlier versions of Visual C++ literally forced you to write non-compliant C++ code. Therefore, it's unlikely that an existing Visual 6.0 app will compile as-is with Visual C++ 8.0 (the C++ compiler of Visual Studio 2005). Therefore, your first step is to review the code and locate potential problems. Before you make any changes to the code, my advice is to review the entire code base and systematically mark all code sections that might be incompatible with Visual Studio 2005. Only then should you make the necessary repairs. It's better to repair incompliant code in several passes, each dealing with a different category of fixes. For example, your first pass may focus on for-loops, the next pass on exception handling, and so on. There are three reasons for splitting the code repairs to separate sessions:
Team Work: Developers specializing in different categories can work on the same code simultaneously.
Coding Standards: It's easier to enforce a uniform coding standard when focusing on one feature at a time.
Keyword-based Lookup: Each category is typically associated with a specific C++ keyword (e.g., to locate all for-loops, search for the keyword for).
Some of the necessary code fixes are rather straightforward. These include for-loops, pointers to member functions, the deprecated "default to int" rule, and exception handling. Let's see what these all mean.
for-loops: In pre-standard C++, variables declared in a for-loop were visible from the loop's enclosing scope. This behavior is still maintained in Visual C++ 6.0:
for (int i=0; i<MAX; i++)
int j=i; //allowed in VC++ 6.0
However, in Visual Studio 2005, the scope of i is restricted to the for-loop. If you want to refer to this variable from the enclosing scope, move its declaration outside the for-loop:
for (; i<MAX; i++)
int j=i; //OK
Figure 1. Exception Handling: This image shows how to override the default exception handling command line flag.
Declarations of pointers to members: In pre-standard C++, it was possible to take the address of a member function without using the & operator:
void (S::*pmf)() = S::func; //allowed in VC++ 6.0
In Visual Studio 2005, the & is mandatory:
void (S::*pmf)() = &S::func; //OK
Tip: To locate problematic code, search for the tokens ::* and ::.
"default to int": Pre-standard C++ (and all C variants predating C99), use the "default to int" rule when declarations of functions and variables do not contain an explicit datatype. This behavior is maintained in Visual C++ 6.0 as the following declarations show:
const x=0; //implicit int
static num; // implicit int
myfunc(void *ptr); //implicit return type int
In Visual Studio 2005, you have to specify the datatype explicitly:
const int x=0;
static int num;
int myfunc(void *ptr);
Tip: To locate incompliant code of this category, compile your app with Visual Studio 2005 and look for compilation errors about a missing datatype in a declaration.
Exception Handling: Older versions of Visual C++ happily mixed standard C++ exceptions with the asynchronous Structured Exception Handling (SEH). Consequently, a catch(...) block might catch not just a C++ exception created by a throw statement, but also an asynchronous SEH e.g., access violation. Not only is this behavior incompliant, it makes debugging more difficult. Visual Studio 2005 fixes this loophole. It's now possible to specify whether a catch(...) handler should catch only C++ exceptions by using the default /EHsc flag (this is the recommended option), or maintain the non-standard behavior of Visual C++ 6.0 by using the /EHa flag (see Figure 1).
Author's Note: The fixes shown here don't reflect all of the changes in Visual Studio 2005. For a complete list, consult Visual Studio 2005 homepage. Also, I have focused on core C++ features. Other Visual C++-specific changes such as multithreaded CRTs, deprecated APIs etc., aren't discussed here.