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?
#define DECLARE_HUNGARIAN( cls ) typedef cls const & rc##cls; \
typedef cls * p##cls;
Now you’ve made the following code possible:
DECLARE_HUNGARIAN( MyClass )
pMyObject bar();
Macro Functions
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:
#define MIN(x,y) ( (x) < (y) ? (x) : (y) )
#define MAX(x,y) ( (x) > (y) ? (x) : (y) )
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?
int n = SQUARE( 2 + 3 );
Ouch this is not what we intended:
int n = 2 + 3 * 2 + 3;
But using parenthesis it is correct again:
int n = (2 + 3) * (2 + 3)
Next: Conditional Compilation >>
More C++ Articles
More By J. Nakamura