Defining a Macro

Problem

You want to define the preprocessor symbol name, assigning it either an unspecified value or the value value.

Solution

The compiler options for defining a macro from the command line are shown in Table 1-16. Instructions for defining a macro from your IDE are given in Table 1-17. To define a macro using Boost.Build, simply add a property of the form name[=value] to your target's requirements, as shown in Table 1-15 and Example 1-12.

Table 1-16. Defining a macro from the command line

Toolset

Option

All

-Dname[=value]

Table 1-17. Defining a macro from your IDE

IDE

Configuration

Visual C++

From your project's property pages, go to Configuration Properties images/U2192.jpg border=0> C/C++ images/U2192.jpg border=0> Preprocessor and enter name[=value] under Preprocessor Definitions, using semicolons to separate multiple entries.

CodeWarrior

From the Target Settings Window, go to Language Settings images/U2192.jpg border=0> C/C++ Preprocessor and enter:

#define name[ = value]  

in the area labeled Prefix Text.

C++Builder

From Project Options, go to Directories/Conditionals and enter name[=value] under Preprocessor Definitions, using semicolons to separate multiple entries.

Dev-C++

From Project Options, select Parameters and enter:

-D name[ = value]  

under C++ Compiler.

 

Discussion

Preprocessor symbols are used frequently in C++ source code to allow a single collection of source files to be used with several build configurations or operating systems. For example, suppose you want to write a function that checks whether a file is a directory. Currently, the C++ standard library does not provide the functionality necessary to perform this task; consequently, your function will need to make use of platform specific features. If you want your code to work both on Windows and on Unix, you'll have to make sure that the code that makes use of Windows-specific features is not visible to the compiler when compiling on Unix, and vice versa. The usual way to achieve this is through conditional compilation , as illustrated in Example 1-25.

Example 1-25. Conditional compilation using predefined macros

#ifdef _WIN32 # include #else // Not Windows - assume we're on Unix # include #endif bool is_directory(const char* path) { #ifdef _WIN32 // Windows implementation #else // Unix implementation #endif }

On Windows, all the toolsets except the Cygwin port of GCC define the macro _WIN32; macros defined automatically in this way are known as predefined macros . Example 1-25 uses the predefined macro WIN32 to determine which operating system it is being compiled under and to enable the appropriate platform-specific code.

Often, however, the configuration information necessary to perform this kind of conditional compilation is not available as predefined macros. In such cases, it's necessary to introduce your own macros and to give them appropriate values using the methods shown in Table 1-15, Table 1-16, and Table 1-17. A good example is Example 1-2. On Windows, you want the function georgeringo( ) to be declared with the attribute _ _declspec(dllexport) when the DLL georgeringo.dll is being built, but with the attribute _ _declspec(dllimport) otherwise. As described in Recipe 1.4, you can achieve this effect by defining the preprocessor symbol GEORGERINGO_DLL from the command line when building the DLL, but not when compiling code that uses the DLL.

When you fail to specify a value for a macro, most compilers assign it the value 1, but others assign it an empty value. When macros are used to enable conditional compilation as in Example 1-25, this difference is not important; if you really need a macro to expand to a particular value, however, you should specify that value explicitly using the syntax -D=.

 

See Also

Recipe 1.4, Recipe 1.9, Recipe 1.12, and Recipe 1.17

Категории