Sunday, January 27, 2013

C preprocessor

I will mention 3 useful features of the c preprocessor that can be used to make a program more customizable:
  1. Stringification
  2. Concatenation
  3. Varadic macros
Stringification can be used to turn an expression into a string, surrounded by double quotes.
To do this we use # in front of the macro argument that we want to stringify:
#define STRINGIFY(S) #S
This will turn the expression STRINGIFY(2+3) into "2+3".
You can use it for something even more complex like this:
#define STRINGIFY(S) #S
const char str[] = STRINGIFY(int main()
{
  return 0;
});
It should be noted that all the whites-paces will be trimmed intro a single space character.

Concatenation is useful when used with the stringify feature. We can use it to merge 2 strings into a single one by using ## like so:
#define CONCAT(A,B) A ## B
This will turn the expression CONCAT("The result is ", STRINGIFY(2+3)) into "The result is 2+3".

Varadic macros are macros with a variable number of arguments.
These can be useful is we want a custom debug function:
#ifndef DEBUG
  #define dprintf(...) do{}while(0)
#else
  #define dprintf(fmt, ...) \
    fprintf(stderr, fmt, __VA_ARGS__)
#endif
In this example, __VA_ARGS__ will represent the parameters given to the dprintf macro. Based on the definition of DEBOG, calls to dprintf will either be converted to fprintf or be completely removed by the compiler.
We can go a step further with our debug function by including the line and file of the call.
#ifndef DEBUG
  #define dprintf(...) do{}while(0)
#else
  #define dprintf(fmt, ...) \
    fprintf(stderr, "[ERROR %s at %d] " fmt, __FILE__, __LINE__, __VA_ARGS__)
#endif
The __LINE__ and __FILE__ macros are expanded to represent the file and line number of the call of dprintf, NOT the declaration. It should also be noted that there is no coma before the fmt argument. This is done so that the C compiler will concatenate the 2 strings.

No comments:

Post a Comment