Jump to content

Check out our Community Blogs

Register and join over 40,000 other developers!

Recent Status Updates

View All Updates

- - - - -

preprocessor directives


  • Please log in to reply
1 reply to this topic

#1 Chinmoy


    CC Addict

  • Just Joined
  • PipPipPipPipPip
  • 365 posts

Posted 26 March 2008 - 04:56 AM


Preprocessor directives are not program statements but directives for the preprocessor. They always start with a #(pound) symbol and are compiled before the execution of the main() function.

The compiler expects the preprocessor to be a single line of code. No semicolon is expected at the end of a preprocessor directive. In case a preprocessor directive has to extend beyond a single line this can be done by preceding the newline character at the end of the line by a backslash (\).

1> macro definitions (#define, #undef)::

To define preprocessor macros we can use #define. Its format is:

#define identifier value

When the preprocessor encounters this identifier in the program, it replaces any occurrence of this identifier in the rest of the code by replacement value. This replacement value can be an expression, a statement, a block or simply anything. The preprocessor replaes the necessary value judging by the value supplied to the identifier. Like if we supply an integer to the identifier it will function as an integer replaecment.

#define size 100
int table1[size];
int table2[size]; 

After the preprocessor has replaced size, the code becomes equivalent to:

int table1[100];
int table2[100]; 

Thus the word size is a macro for the value of size.

Now asa variation #define can also be used to define a macro function.
Eg ::

#define max(a,b) a>b?a:b

This would replace any occurrence of max followed by two arguments by the replacement expression, but also replacing each argument by its identifier, Thus behaving exactly like a function.

// function macro

#include <iostream.h>
#define max(a,b) ((a)>(b)?(a):(b))

int main()
  int x=5, y;
  y= max(x,2);
  cout << y << endl;
  cout << max(7,x) << endl;
  return 0;

Macro definitions cannot be modified in the code anywhere else than the preprocessor directives. The only modification allowed is a #undef to flush out the macro.

#define size 100
int table1[size];

#undef size

#define size 200
int table2[size];

This would generate the same code as:

int table1[100];
int table2[200];

2> Function macro definitions ::

Function macro definitions accept two special operators (# and ##) in the replacement sequence:
If the operator # is used before a parameter is used in the replacement sequence, that parameter is replaced by a string literal (as if it were enclosed between double quotes)

#define str(x) #x
cout << str(test);

This would become ::
cout << "test";

The operator ## concatenates two arguments leaving no blank spaces between them:

#define glue(a,b) a ## b
glue(c,out) << "test";

This would be same as the last one.

The macro definition is checked before the preprocessor in c. Thus there are no syntax checks. Macros can thus get very tricky in use and they are heavy on resources also if used in large numbers.

3>Conditional inclusion directives::

(#ifdef, #ifndef, #if, #endif, #else and #elif)

These directives allow to include or discard part of the code of a program if a certain condition is met.

#ifdef allows a section of a program to be compiled only if the macro that is specified as the parameter has been defined, no matter which its value is. For example:
#ifdef size
int table[size];

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

#ifndef serves for the exact opposite: the code between #ifndef and #endif directives is only compiled if the specified identifier has not been previously defined. For example:
#ifndef TABLE_SIZE
#define TABLE_SIZE 100
int table[TABLE_SIZE];

In this case, if when arriving at this piece of code, the TABLE_SIZE macro has not been defined yet, it would be defined to a value of 100. If it already existed it would keep its previous value since the #define directive would not be executed.

The #if, #else and #elif (i.e., "else if") directives serve to specify some condition to be met in order for the portion of code they surround to be compiled. The condition that follows #if or #elif can only evaluate constant expressions, including macro expressions. For example:

#if TABLE_SIZE>200
#define TABLE_SIZE 200
#elif TABLE_SIZE<50
#define TABLE_SIZE 50
#define TABLE_SIZE 100
int table[TABLE_SIZE]; 

Here the whole structure of #if, #elif and #else chained directives ends with #endif.

4>Line control:: (#line)

When we compile a program and some error happen during the compiling process, the compiler shows an error message with references to the name of the file where the error happened and a line number, so it is easier to find the code generating the error and rectify it based on teh error type and message.

The #line directive allows us to control both things, the line numbers within the code files as well as the file name that we want that appears when an error takes place. It is thus similar to exeption handling. Its format is:

#line number "filename"

Where number is the new line number that will be assigned to the next code line. The line numbers of successive lines will be increased one by one from this point on.

"filename" is an optional parameter that allows to redefine the file name that will be shown. For example:
#line 40 "Incorrect assignment"
int a?; 

This code will generate an error that will be shown as error in file "incorrect assingment", line 40.

5>Error directive:: (#error)

This directive aborts the compilation process when it is found, generating a compilation the error that can be specified as its parameter:
#ifndef __cplusplus
#error A C++ compiler is required!

Here the compilation process aborts if the macro name __cplusplus is not defined (this macro name is defined by default in all C++ compilers).

6>Source file inclusion:: (#include)

This header is the most widely and commonly used. It specifies the file to which the linker links the preprocessor of the code for source inclusion. There are two ways to specify a file to be included:
#include "file"
#include <file>

The difference between both expressions is the places (directories) where the compiler is going to look for the file.
In the first case where the file name is addressed in 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.
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.

This is why, standard header files are usually included in angle-brackets, while other specific header files are included using quotes.

Attached Thumbnails

  • untitled.JPG

Attached Files

  • Attached File  dir1.cpp   194bytes   225 downloads

  • 0

God is real... unless declared an integer

my blog :: http://techarraz.com/

#2 se7en


    CC Regular

  • Member
  • PipPipPip
  • 32 posts

Posted 21 June 2010 - 03:32 AM

Thanks for this awesome tutorial!!!
  • 0