Pre-processor symbols

To get access to the tracing, asserts, and reporting facilities in your code, you have to enable the debugging runtime library, and this is done by using the /MDd, /MTd, or /LDd compiler switches, which will define the _DEBUG pre-processor symbol. The _DEBUG pre-processor symbol enables a lot of facilities, and conversely, not defining this symbol will help in optimizing your code.

    #ifdef _DEBUG 
cout << "debug build" << endl;
#else
cout << "release built" << endl;
#endif

The C++ compiler will also provide information through some standard pre-processor symbols. Most of these are useful only for library writers, but there are some that you may want to use.

The ANSI standard says that the __cplusplus symbol should be defined when the compiler is compiling code as C++ (rather than C), and it also specifies that the __FILE__ symbol should contain the name of the file and that __LINE__ symbol will have the line number at the point where you access it. The __func__ symbol will have the current function name. This means that you can create tracing code like the following:

    #ifdef _DEBUG 
#define TRACE cout << __func__ << " (" << __LINE__ << ")" << endl;
#else
#define TRACE
#endif

If this code is compiled for debugging (for example, /MTd) then the cout line will be put inline whenever TRACE is used; if the code is not compiled for debugging then TRACE will do nothing. The __func__ symbol is simply the function name, it is not qualified, so if you use it in a class method it will provide no information about the class.

Visual C++ also defines Microsoft-specific symbols. The __FUNCSIG__ symbol gives the complete signature including the class name (and any namespace names), the return type, and parameters. If you just want the fully qualified name, then you can use the __FUNCTION__ symbol. A symbol that you will see frequently in the Windows header files is _MSC_VER. This has a number that is the version of the current C++ compiler, and it is used with a conditional compilation so that newer language features are only compiled with a compiler that supports them.

The Visual C++ project pages define build macros with names like $(ProjectDir) and $(Configuration). These are used only by the MSBuild tool so they are not automatically available in a source file during compilation, however, if you set a pre-processor symbol to the value of a build macro, the value will be available through that symbol at compile time. The system environment variables are also available as build macros, so it is possible to use them to influence the build. For example, on Windows the system environment variable USERNAME has the name of the current logged on user so you could use it to set a symbol and then access that at compile time.

In the Visual C++ project pages, you can add a Preprocessor Definition on the C/C++ preprocessor project page called:

    DEVELOPER="$(USERNAME)"

Then, in your code, you could add a line using this symbol:

    cout << "Compiled by " << DEVELOPER << endl;

If you are using a make file, or just invoking cl from the command line, you can add a switch to define the symbol like this:

    /DDEVELOPER="$(USERNAME)"

Escaping the double quotes here is important because without them the quotes are eaten by the compiler.

Earlier, you saw how the #pragma message and #error directives can be used to put messages into the output stream of the compiler. When you compile code in Visual Studio the compiler and linker outputs will appear in the output window. If the message is in the form:

    path_to_source_file(line) message

where path_to_source_file is the full path to the file, line is the line number where the message appears. Then, when you double click on this line in the output window, the file will be loaded (if not already) and the insertion point placed on the line.

The __FILE__ and __LINE__ symbols provide you with the information that you need to make #pragma message and #error directives more useful. Outputting __FILE__ is simple because it is a string and C++ will concatenate string literals:

    #define AT_FILE(msg) __FILE__ " " msg 

#pragma message(AT_FILE("this is a message"))

The macro is called as part of the pragma to format the message correctly; however, you cannot call the pragma from a macro because the # has a special purpose (that will be of use in a moment). The result of this code will be something like:

    c:Beginning_C++Chapter_10test.cpp this is a message

Outputting __LINE__ via a macro requires a bit more work because it holds a number. This issue is a common one in C, so there is a standard solution using two macros and the stringing operator, #.

    #define STRING2(x) #x 
#define STRING(x) STRING2(x)
#define AT_FILE(msg) __FILE__ "(" STRING(__LINE__) ") " msg

The STRING macro is used to expand the __LINE__ symbol to a number and the STRING2 macro to stringify the number. The AT_FILE macro formats the entire string in the correct format.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset