Conditional Compilation

Even if macros go completely out of favor, the C++ preprocessor allows you to conditionally compile code, depending on the environment. For example, usually there are debug and release builds of a program; debug builds contain all the symbolic information for the debugger, and release builds are optimized to be fast and/or small. Sometimes you might want slightly different behavior from the debug version of the program. For example, you might have output statements that are for testing only. You might have assert()s, and you don't want to burden the release version with the extra code. In these cases, it is useful to exclude code from the compilation.

The #ifdef and #ifndef Directives

The #ifdef directive directs the preprocessor to include the following code, up to a matching #else or #endif, if the macro symbol following it is defined:

#ifdef _DEBUG
  // trace the progress!
    Cerr << "iteration = " << iter << endl;
 #endif

In this case the programmer only wants to see the progress of a loop in the debug version, when the symbol _DEBUG is defined.

The #ifndef directive works similarly to the #ifdef directive, except it includes code if a symbol is not defined. A very important use of this is to prevent a header file from being included more than once. (In fact, this is so common that it's worth writing a small program to generate new header files.) Standard compilers do not allow you to redeclare variables, classes, and so on. The following prevents a header file from being included more than once:

// header.h
#ifndef __HEADER_H
#define __HEADER_H
 ...(your code goes here)...
#endif

The first time around, the macro __HEADER_H is defined (it does not need a value), and the code is included. The second time around, the macro is defined and the code is not included. In an interactive environment, this can be problematic, so the UnderC load command (#l) automatically undefines any macros defined in the module.

The symbol __UNDERC__ is available only in the UnderC environment, so you can write code that can properly compile under old compilers, which don't have namespaces:

#ifdef __UNDERC__
  #include <iostream>
  using namespace std;
#else
  #include <iostream.h>
#endif

This ability to configure source to compile properly in all sorts of environments and all sorts of machines was a strong reason that C became so dominant a language. (It is important to note that the compiler does not see any excluded code, so there is no runtime penalty. Conditional compilation has nothing to do with C++ if-else statements.)

Another simple application is to produce an assert() statement. These can be very useful in debugging; if the asserted statement is no longer true, then the assert() will stop the program, giving the program file and line number, together with the failed statement.

int getval(int arr[], int n, int idx) {
  assert(idx >= 0 && idx < n);
  return arr[idx];
}

A program containing getval() would terminate with the following error message when the index idx is out of range:

assertion failed: test_getval.cpp; idx >= 0 && idx < n

The standard assert() is available from the <assert.h> system header, but the following is a simplified implementation of assert(), which shows how assert() statements literally expand to nothing when you don't need them:

#ifdef _DEBUG
  #define assert(expr)  if (!(expr))  __assert(__FILE__ "; " #expr)
#else
 #define assert(expr)
#endif

A simple version of the function __assert() puts out the message and terminates the program with exit(), and would look like this:

void __assert(char *msg)
{
   cerr << "assertion failed: " << msg << endl;
   exit(-1);
}

The #if Directive

The #if directive is a generalization of #ifdef, and it allows you to specify a conditional expression. This looks very much like a C/C++ expression, but it is restricted to compile-time constants that involve macros. The special function defined() can be used to inquire about a macro. For example,

#if defined(_DEBUG) && _TRACE > 2
#message "Now debugging..."
#endif

Currently UnderC does not support this full syntax.

Note the #message directive; it is occaisonally useful to print out a message when the compiler is preprocessing. This will appear when the programmer builds the code.

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

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