In this article, we examine instructions given to the preprocessor and see how they are used in general. The preprocessor handles your code before the compiler interprets it. If you have been wondering just what the preprocessor is used for, this article explains.
C++ Preprocessor: The Code in the Middle - String Manipulation (Page 3 of 6 )
When you use the preprocessor for string substitution it can do more than simply replace tokens with values. It is possible to quote strings that were passed as a parameter and you can concatenate two strings together into one.
The stringizing operator (#) substitutes the macro variable following it with its value and puts quotes around it.
For example:
#define LOG(x) std::cout << #x << std::endl
When used like:
LOG(Hello World);
will be substituted into and presented to the compiler as:
std::cout << “Hello World” << std::endl;
With the concatenation operator (##) you can tie separate strings into a new single identifier. There are many useful things you can do with this and we’ll actually need this operator when we implement customizable streams.
It is also possible to drive things to extremes. There is a company I know of that requires in its coding standard that you use their ‘Simplified Hungarian naming convention’. This means that a function that takes a const reference to an object MyClass doesn’t look like:
void foo ( MyClass const &obj );
But in their code looks like:
void foo ( rcMyClass obj );
While this might save you some typing effort, I wouldn’t recommend making such drastic changes to the C++ language. Still as an example… how did it ever get this far?
The ‘#define’ directive is very versatile and powerful, given the simple fact that it can replace one string with another string: we can create macro functions.
#define SQUARE(x) ( (x) * (x) )
The MIN and MAX macros are also often quoted as examples:
You have to remember that all this does is string substitution, and any form of type checking is completely lacking!
An important note is that the opening parenthesis for the parameter list must immediately follow the macro name. There are no spaces allowed, since the preprocessor will otherwise consider it to be a regular string substitution.
In case you wonder why the parameters are all wrapped in parenthesis again, consider what would happen if we’d defined SQUARE as:
#define SQUARE(x) ( x * x )
Now why does the following give a result of 11 instead of 25?