Also known as: Making gibberish do your work for you.

Since it's snowing out and I have nothing better to do, I will share some horrible-looking 'best practices' for the C preprocessor here.

First off, for the newbies, we need to clear up a few things about what you can do with CPP.

Strings and stringizing
The C compiler takes any two strings next to each other, and makes one string of them.

The preprocessor puts quotes around macro arguments with the stringizing operator.

Code:
const char* sz = "This is "     "a string.";
(sz is "This is a string.")

#define MakeString( a )  # a
const char* sz2 = MakeString( Bob ) " Spork";
(sz2 is "Bob Spork")

/** 
 * \brief Interpret, then convert a preprocessor directive (d) into a string  
 * \param d Token to expand and make a string from
**/
#define ppTokStr(d)			_ppTokStr(d)
#define _ppTokStr(d)				_ppTokStra(d)
#define _ppTokStra(d)					#d


#define bob chuck
const char* sz3 = "Up" MakeString( Bob ) ;
(sz2 is "Upchuck")

/**
 * It's helpful to have preprocessor tokens that do nothing.
**/
#define ppNULL

#ifdef _MSC_VER
/**
 * \brief Output a string with file and line compatible with the local IDE - naiive 
 * \param txt Text to append after (or ppNULL )
 *
 * Note for MSVC you MUST turn off 'edit and continue' and 'incremental build', or __LINE__ doesn't expand right
 * You should do so anyway because MSVC will choke on complex macro expansion, which is what this whole template library is.
**/
#define ppFileLine(txt)		__FILE__ "(" ppTokStr(__LINE__) ") : " txt
#else
/**
 * \brief Output a string with file and line compatible with the local IDE - naiive 
 * \param txt Text to append after (or ppNULL )
**/
#define ppFileLine(txt)		__FILE__ ":" ppTokStr(__LINE__) ": " txt
#endif

#define ppFileLine(txt)		__FILE__ "(" ppTokStr(__LINE__) ") : " txt
Token pasting

Token pasting allows you to take two macro arguments and glue them together. In this example, the concatentation is put off through extra levels of call to do the concatenation. This is so the higher level call can expand the arguments before token-pasting them. This lets you define and expand things before they're pasted together.

Code:
#define ppConcat(a,b)		_ppConcat(a,b)
#define _ppConcat(a,b)			_ppConcata(a,b)
#define _ppConcata(a,b)			a ## b

ppConcat(bob,cat) makes: bobcat

#define bob blah
ppConcat(bob,cat) makes: blahcat
Doing things several times
Code:
#define ppOps( op, count ) ppConcat( _ppOP, ppToken(count) )(op)
	#define _ppOP0(op)	
	#define _ppOP1(op)	op 
	#define _ppOP2(op)	op op 
	#define _ppOP3(op)	op op op 
	#define _ppOP4(op)	op op op op 
	#define _ppOP5(op)	op op op op op 
	#define _ppOP6(op)	op op op op op op 
	#define _ppOP7(op)	op op op op op op op 
	#define _ppOP8(op)	op op op op op op op op 
	#define _ppOP9(op)	op op op op op op op op op 
	#define _ppOP10(op)	op op op op op op op op op op 
		#define _ppOP11(op) _ppOP10(op) _ppOP1(op)
		#define _ppOP12(op) _ppOP10(op) _ppOP2(op)
		#define _ppOP13(op) _ppOP10(op) _ppOP3(op)
		#define _ppOP14(op) _ppOP10(op) _ppOP4(op)
		#define _ppOP15(op) _ppOP10(op) _ppOP5(op)
		#define _ppOP16(op) _ppOP10(op) _ppOP6(op)
		#define _ppOP17(op) _ppOP10(op) _ppOP7(op)
		#define _ppOP18(op) _ppOP10(op) _ppOP8(op)
		#define _ppOP19(op) _ppOP10(op) _ppOP9(op)
	#define _ppOP20(op) _ppOP10(op) _ppOP10(op)
    	/* And on and on, however long you want to go */

/*
 * \brief Constant: Raise some constant base value, 'b' to the xth power (ppExp(10,3) = 1000)
 * \param b Base value
 * \param x Power; must be an integer constant (i.e. 3, not 'x')
 */
#define ppExponent( b, x )	( 1 ppOps( * (b), x ) )
So, (1 ppOps( * 10, 3 )) is made into (1 * 10 * 10 * 10) by the preprocessor, and the C compiler makes a constant value of 1000 from that when it evaluates the constants.

Macros to macros (to macros...)

You can use the preprocessor like a primitive database, and query rows and columns based on the content of a macro that you either painstakingly typed, or had a CASE tool spew forth for you (for instance that 'ppOps' mess is made by a 50 line tool that just spews that mess out for me, so I don't have to type it).

By making lists of things like this, you can keep track of a lot of things you need to make many seperate tables out of, all in one place, and you can extract the content where you need it.

Code:
#define table_o_crap( def ) \
   def( Bob, "123-4567", 48,  12 ) \
   def( Ann, "456-7890", 56,  11 ) \
   def( Cal,  "867-5309", 35,  9 ) \
   def( Bob, "333-EATS", 72,  214 ) \

#define GetNameEnum( name, phone, age, etc ) name
#define GetNameCase( name, phone, age, etc ) case name:
#define GetNameString( name, phone, age, etc ) #name
#define GetPhone( name, phone, age, etc ) phone
#define GetAge( name, phone, age, etc ) age
#define GetEtc( name, phone, age, etc ) etc
#define GetString( name, phone, age, etc ) #name " Phone:" phone, " Age:" #age " Etc:" #etc "\n"
#define GetStruct( name, phone, age, etc ) { #name, phone, age, etc },
Getting Obscene
You can use the preprocessor to do a lot of interesting things. There are two ways to do the following, but I'm going to show you the 'hard' (to use) way first.


Code:
/*
 * Establish template patterns
 */

#define DEF_DECL( item )		decl_##item
#define decl_BEGIN( classname )				typedef struct classname {
#define decl_SCALAR( type, label, value )		type label;
#define decl_COMPOUND( type, label )			type label;
#define decl_END( classname )				} classname;\
											extern void classname##_init( classname* self );\
											extern void classname##_destroy( classname* self );\


#define DEF_INIT( item )		init_##item
#define init_BEGIN( classname )				void classname##_init( classname* self ) {
#define init_SCALAR( type, label, value )		self->label = (value);
#define init_COMPOUND( type, label )			type##_init( &self->label );
#define init_END( classname )				}
 
#define DEF_DESTROY( item )		destroy_##item
#define destroy_BEGIN( classname )			void classname##_destroy( classname* self ) {
#define destroy_SCALAR( type, label, value )   
#define destroy_COMPOUND( type, label )			type##_destroy( &self->label );
#define destroy_END( classname )            }


/* And serialization, XML I/O, database, dispatch, encoding, etc functions based on this pattern! */

#define CLASS_DECLARE( class_decl )		class_decl( DEF_DECL )
#define CLASS_IMPLEMENT( class_decl )	\
class_decl( DEF_INIT ) \
class_decl( DEF_DESTROY ) \

#define XYZ_DECL( def ) \
def( BEGIN( XYZ ) )\
   def( SCALAR( float, X, 0.0f ) )\
   def( SCALAR( float, Y, 0.0f ) )\
   def( SCALAR( float, Z, 0.0f ) )\
def( END( XYZ ) )

#define MYSTRUCT_DECL( def ) \
def( BEGIN( MyStruct ) )\
   def( SCALAR( int, id, ++globalID ) )\
   def( COMPOUND( XYZ, location ) )\
def( END( MyStruct ) )

CLASS_DECLARE( XYZ_DECL );
CLASS_DECLARE( MYSTRUCT_DECL );


int globalID = 0;

CLASS_IMPLEMENT( XYZ_DECL );
CLASS_IMPLEMENT( MYSTRUCT_DECL );


int main( void )
{
	MyStruct mys;
	MyStruct_init( &mys );
	return 0;
}
Here's the preprocessor output... (piped through 'indent', else a LOT of these would be one-liner spew).

Code:
cl /E ppSample.cpp|indent

typedef struct XYZ
{
  float X;
  float Y;
  float Z;
} XYZ;
extern void XYZ_init (XYZ * self);
extern void XYZ_destroy (XYZ * self);;
typedef struct MyStruct
{
  int id;
  XYZ location;
} MyStruct;
extern void MyStruct_init (MyStruct * self);
extern void MyStruct_destroy (MyStruct * self);;


int globalID = 0;

void
XYZ_init (XYZ * self)
{
  self->X = (0.0f);
  self->Y = (0.0f);
  self->Z = (0.0f);
} void

XYZ_destroy (XYZ * self)
{
};
void
MyStruct_init (MyStruct * self)
{
  self->id = (++globalID);
  XYZ_init (&self->location);
} void

MyStruct_destroy (MyStruct * self)
{
  XYZ_destroy (&self->location);
};


int
main (void)
{
  MyStruct mys;
  MyStruct_init (&mys);
  return 0;
}
Anyway, in a large project with a lot of this auto-generated code, a whole lot of grunty work can be done by the preprocessor, so when you add a new member to a 'class', you don't need to remember to add/change pieces of code scattered all over the project. This technique works just as well for C++.

Generally, you would want more kinds of scalars (as well as thoroughly defined scalar types), such as ones that are supposed to be serialized or stored in a database, versus ones that are not. You may also want to declare various functions through the class factory, so that 'finding' them (or virtualizing them) becomes trivial.

Next post: The 'easy' way to do what I just showed you (though it takes a lot more code to implement). It makes it possible to step through the code, sort of like a C++ template, without piping it through the preprocessor and compiling the output.