Sunday, February 17, 2008

Working with Macros in C

More about C Macros

I do agree that everybody who worked in C, knows about pre-processor and macros.

But I thought of sharing some tips about preprocessor and the gcc options to control the preprocessor output.

Here is a simple usage of macros

#define sum(a, b) a+b

int main () {
int k = sum(10,20)*10;
return k;
}

Yes, the output is 210 (not 300, the famous interview question for freshers).

Let us check the output of preprocessor and see that the result is 210...

gcc takes an argument -E that output the preprocessor output.

Compile the above program using gcc -E test.c -o test.txt
Open the test.txt file and the output is

int main () {
int k = 10 +20*10;
return k;
}

Now you see how the #define is replaced with the value... quite useful for complex preprocessor commands.

Thought of add couple of other useful preprocessor commands.

For fun let us write a application that merges two XML files (by adding a root tag)... a cool application (not really, you can do it easily using a simple shell script ;-( ).

Combine two or more xml files using gcc?
Very simple.

sample_app.x

#include FILE1
#include FILE2

compile it using:
gcc -x c -P -DFILE1=\"text1.xml\" -DFILE2=\"text2.xml\" -DROOT_TAG=root1 -E sample_app.x -o result.xml
make sure that the text1.xml and text2.xml files are available. The output will be in result.xml (defined in -o option).
we use the following compile options:
-x c here our input file is sample_app.x, and gcc doesn't know whether it is C or C++ or Java, so mention that the language is c using -x option
-P (don't generate # line directives)
-D define the macro
-E only preprocess, don't compile and link
-o output file

Even though the above example is very simple, there are couple of very wonderful technologies that are build using this like
1) SQC uses this kind of logic (you too can write your own SQC compiler with some trouble).
2) Variable-length parameter list (called varags) also uses preprocessor (if you are not sure about this, just check that printf (a c function), can take any number of arguments)... you can also create variable length argument functions.
3) Template engines. just check the google CTemplate or Java Velocity (even though they are not written using this).

Some more tools while using preprocessor.
Predefined Macros
__LINE__ current line number
__FILE__
__DATE__ current date
__TIME__
__cplusplus defined if using a c++ compiler

Other useful macros defined by gcc
__SIZEOF_INT__
__SIZEOF_LONG__
__SIZEOF_LONG_LONG__
__SIZEOF_SHORT__
__SIZEOF_POINTER__
__TIMESTAMP__
__INCLUDE_LEVEL__

Stringizing using #
Common usage of this is escaping double quotes.
For example use what to copy a string
Error: "File Not found" - please check " test.xml"
We write:
printf("Error: %s\n", "\"File Not found\" - please check \"test.xml\"");
see the code looks ugly because of escaping double quotes, use Preprocessor to automatically include escape characters.

# define Q (x) #x
printf("Error: %s\n", Q("File Not found" - please check "test.xml")); // see we are not escaping any double quotes
Check the result using the same gcc -E option.

Token pasting using ##
A good example in gcc document related to this.
Say out want to generate a commands list like:
struct command commands[] =
{
{ "quit", quit_command },
{ "help", help_command },
{ "run", run_command }
...
};

where struct command
{
char *name;
void (*function) (void); // hope you are aware of function pointer...

// I can't give you more details because I too don't much about it :-(
};

you can define as:
#define COMMAND(NAME) { #NAME, NAME ## _command }

struct command commands[] =
{
COMMAND (quit),
COMMAND (help),
COMMAND (run);
...
};

Just run the above example using gcc -P -E test2.c -o test2.text and see the output!

No comments:

Copyright (c) 2008 - Suresh