C++ Preprocessor Directives

Introduction
Preprocessor

The pre-processor is a text processor that manipulates the text of a source file as part of the first part(stage) of translation. The compiler normally invokes the pre-processor in its first pass, the pre-processor may also be invoked separately to process text without compiling.

Pre-Processor directives These are special words which are evaluated and executed before compilation of code begins, therefore the pre-processor digests all these directives before any code is generated by the statements.

They are lines included in the code of our programs that are not program statements but directives for the pre-processor. The lines are preceded by a hash sign (#). These can be used to make the compiler compile files other than the ones that the programmer explicitly compiles on the command line, effectively making several files one file. They allow a c++ program to use or manipulate data using built in functions or functions declared in other files.

#define
It is a constant definer, it is used to specify global constants. Syntax: Example:
 * 1) define variablename value
 * 1) define getmin(a,b) a<b?a:b

Conditional Directives
#ifdef, #ifndef, #if, #endif, #else and #elif

These directives allow the inclusion or discarding part of the code of a program if a certain condition is met. They are selective in nature.

#ifdef
Allows a certain code in the program to be compiled only if the macro that is specified as the parameter has been defined, no matter what its value is.

Example: int table[NAMES_SIZE];
 * 1) ifdef NAMES_SIZE
 * 1) endif

In this case, the line of code int table[MANES_SIZE]; is only compiled if the NAMES_SIZE was previously defined with the #define directive, i.e independently of its value. If it was not defined, that particular line will not be included in the program compilation.

#ifndef
The code between #ifndef and #endif directives is only compiled if the specified identifier has not been previously defined. Example:

int table[NAMES_SIZE]; On arriving at this code in the program, if the NAMES_SIZE macro has not been defined yet, it would be defined to a value of 10. If it already existed it would keep its previous value since the #define directive would then not be executed.
 * 1) ifndef NAMES_SIZE
 * 2) define NAMES_SIZE 10
 * 3) endif

#if, #else and #elif directives
They specify some condition to be met in order for the part of code they surround to be compiled. The condition that follows #if or #elif can only evaluate constant expressions, including macro expressions. Example: int table[TABLE_SIZE];
 * 1) if NAMES_SIZE>250
 * 2) undef NAMES_SIZE
 * 3) define NAMES_SIZE 250
 * 1) elif NAMES_SIZE<150
 * 2) undef NAMES_SIZE
 * 3) define NAMES_SIZE 150
 * 1) else
 * 2) undef NAMES_SIZE
 * 3) define NAMES_SIZE 10
 * 4) endif

Note: The whole structure of #if, #elif and #else directives end with #endif directive.

#line
It is a line control directive. When a program is compiled and some error occurs during the compilation process, the compiler displays an error message with references to the name of the file where the error occurred and the line number, this makes it easier to find the code generating the error.

The #line directive allows programmers to control two things, the line numbers within the code files and the file name that we want to appear when an error takes place.

Syntax:
 * 1) line linenumber "nameoffile"

Where linenumber is the new line number that will be assigned to the next code line. The line numbers of successive lines will be increased by one from one to the next from this point on. "nameoffile" is an optional parameter that allows the programmer to redefine the file name that will be displayed.

Example:

int c?;
 * 1) line 23 "Value assignment"

This code will generate an error that will be shown as error in file "Value assignment", line 23.

#error
Is an error directive. This directive aborts the compilation process when it is found, generating a compilation the error that can be specified as its parameter:


 * 1) ifndef __trial
 * 2) error A C++ compiler required!
 * 3) endif

This example aborts the compilation process if the macro name __trial is not defined.

#include
Allows source file inclusion. When the preprocessor finds an #include directive it replaces it by the entire content of the specified file. There are two ways to specify a file to be included: The difference between the two expressions is the places / folders (directories) where the compiler is going to look for the file. If the file name is enclosed between angle-brackets <> the file is searched directly where the compiler is configured to look for the standard header files. Therefore, standard header files are usually included in angle-brackets, while other specific header files are included using quotes.
 * 1) include
 * 2) include "file"

In case the file name is specified between double-quotes, the file is searched first in the same directory that includes the file containing the directive. In case that it is not there, the compiler searches the file in the default directories where it is configured to look for the standard header files.

include
This is a c++ preprocessor directive that allows the program to insert data from the console (screen) into the input stream. The key word cin(console input) and insertion operator >> are used to insert data and the key word cout (console output) and the extraction operator << are used to extract data. Example: int main {  double mark; cin>>mark; cout<

#include
This directive can be used when the program is to only allow data to be read from the console and with no output expected. It can only allow the use of cin and insertion operator but if cout and extraction operator are used then the compiler detects this as an error. Example: int main {  int marks; cin>>marks; marks = marks * 30; return 0; }
 * 1) include

#include
This directive can be used when the program is to only allow data to be output to the console and with no input expected. It can only allow the use of cout and extraction operator but if cin and insertion operator are used then the compiler detects this as an error. Example: using namespace std; int main {  int mark; cout<<mark<<endl; return 0; }
 * 1) include

#import Directive
Is used to incorporate information from a type library into the program. The content of the type library is converted into C++ classes, mostly describing the COM interfaces.

Example:
 * 1) import "filename" [attributes]
 * 2) import [attributes]

"filename" can optionally be preceded by a directory specification. The file name must be an existing file. The difference between the two syntax forms is the order in which the pre-processor searches for the type library files when the path is incompletely specified.

Quoted form
Instructs the preprocessor to look for type library files first in the directory of the file that contains the #import statement, and then in the directories of whatever files that include (#include) that file. The preprocessor then searches along the paths shown below.

Angle-bracket form
Instructs the preprocessor to search for type library files along the following paths:

#The PATH environment variable path list

#The LIB environment variable path list


 * 1) The path that is specified by the /I (additional include directories) compiler option, except it the compiler is searching for a type library that was referenced from another type library with the no_registry attribute.

#
The null preprocessor directive is a single number sign (#) alone on a line. It has no effect.

#pragma
This directive is used to specify diverse options to the compiler. The options are specific for the platform and the compiler you are using.

#undef
The #undef directive removes the current definition of identifier. The subsequent occurrences of the identifier are ignored by the preprocessor. In order to remove a macro definition using #undef, give only the macro identifier ; and do not give a parameter list.

The #undef directive can also be applied to an identifier that has no previous definition. This ensures that the identifier is undefined. The Macro replacement is not performed inside #undef statements.

The #undef directive is paired with a #define directive to create a region in a source program in which an identifier has a special meaning e.g. a specific function of the source program can use manifest constants to define environment-specific values that do not affect the rest of the program. The #undef directive can also work with the #if directive to control conditional compilation of the source program. See The #if, #elif, #else, and #endif Directives.

In the example below, the #undef directive removes definitions of a symbolic constant and a macro. Note: Only the identifier of the macro is given.


 * 1) define WIDTH 70
 * 2) define ADD( n, m ) ((n) + (m))


 * 1) undef WIDTH
 * 2) undef ADD

#using
Imports metadata into a program compiled with /clr. Syntax:
 * 1) using file [as_friend]

"file" can be a file that you import for its managed data and managed constructs. If a .dll file contains an assembly manifest, then all the .dlls referenced in the manifest are imported and the assembly you are building will list file in the metadata as an assembly reference.

If file does not contain an assembly that is if file is a module and if you do not intend to use type information from the module in the current (assembly) application, you have the option of just indicating that the module is part the assembly; use /ASSEMBLYMODULE. The types in the module would then be available to any application that referenced the assembly. Example: // using_assembly_C.cpp // compile with: /clr int main {  B b;   b.Test; }
 * 1) using "using_assembly_B.dll"

Stringizing operator (#)
Causes the corresponding actual argument to be enclosed in double quotation marks. This operator (#) converts macro parameters to string literals without expanding the parameter definition. It is used only with macros that take arguments. If it precedes a formal parameter in the macro definition, the actual argument passed by the macro invocation is enclosed in quotation marks and treated as a string literal. The string literal then replaces each occurrence of a combination of the stringizing operator and formal parameter within the macro definition.

White spaces preceding the first token of the actual argument and following the last token of the actual argument are ignored. Any white spaces between the tokens in the actual argument are reduced to a single white space in the resulting string literal. In that, if a comment occurs between two tokens in the actual argument, it is reduced to a single white space. The resulting string literal is automatically concatenated together with any adjacent string literals from which it is separated only by white space.

Also, if a character contained in the argument usually requires an escape sequence when used in a string literal (i.e the quote mark (") or backslash (\) character), the necessary escape backslash is automatically inserted before the character.

Example: //A macro definition that includes the stringizing operator and a main function that invokes the macro: //Such invocations would be expanded during preprocessing, producing the following code:

int main { printf_s( "Using quotes in the printf function call\n" "\n" ); printf_s( "\"Using quotes when printed to the screen\"\n" "\n" ); printf_s( "\"This example: \\\" prints an escaped double quote\"" "\n" ); }

// stringizer.cpp int main { stringer( Using quotes in the printf function call ); stringer( "Using quotes when printed to the screen" ); stringer( "This sample: \" prints an escaped double quote" ); }
 * 1) include 
 * 2) define stringer( n ) printf_s( #n "\n" )

Example: //how to expand a macro parameter: // stringizer_2.cpp // compile with: /E FB(F B) FB1(F B)
 * 1) define F lmn
 * 2) define B efg
 * 3) define FB(arg) #arg
 * 4) define FB1(arg) FB(arg)

The C++ stringizing operator may not always behave as expected the # Operator for more information.

Charizing operator (#@)
It causes the corresponding argument to be enclosed in single quotation marks and to be treated as a character (it is Microsoft Specific) This operator can be used only with arguments of macros. If #@ precedes a formal parameter in the definition of the macro, the actual argument is enclosed in single quotation marks and treated as a character when the macro is expanded.

Example: causes the statement n = makechar(m); to be expanded to n = 'm';
 * 1) define makechar(n) #@n

NB: The single-quotation character cannot be used with the charizing operator.

Token-pasting operator (##)
This operator allows tokens used as actual arguments to be concatenated to form other tokens. The double-number-sign or "token-pasting" operator (##), which is sometimes called the "merging" operator, is used in both object-like and function-like macros. It permits separate tokens to be joined into a single token and therefore cannot be the first or last token in the macro definition.

If a formal parameter in a macro definition is preceded or followed by the token-pasting operator, the formal parameter is immediately replaced by the unexpanded actual argument. Macro expansion is not performed on the argument prior to replacement.

Then, each occurrence of the token-pasting operator in token-string is removed, and the tokens preceding and following it are concatenated. The resulting token must be a valid token. If it is, the token is scanned for possible replacement if it represents a macro name. The identifier represents the name by which the concatenated tokens will be known in the program before replacement. Each token represents a token defined elsewhere, either within the program or on the compiler command line. White space preceding or following the operator is optional.

Example: int token8 = 8;
 * 1) define paster( n ) printf_s( "token" #n " = %d", token##n )

Calling a macro with a numeric argument like paster( 8 ); the macro yields printf_s( "token" "8" " = %d", token8 ); this becomes printf_s( "token8 = %d", token8 );

defined operator It simplifies the writing of compound expressions in certain macro directives

Reference

 * 1) http://msdn.microsoft.com/en-us/library/79yewefw%28v=VS.80%29.aspx
 * 2) http://msdn.microsoft.com/en-us/library/3sxhs2ty%28v=VS.80%29.aspx