Macros (Part I)
Macros are one of the most important components of C language. You can do some really cool stuff using them. Well of course with great power comes great responsibilities :)
If you've done C programming, you might be well versed with the following line on top of a C program
# include <stdio.h>
This line is responsible for "inserting" the contents of stdio.h file (containing several important structures, global variables and function declarations) in place of the line itself.
This insertion is required if we plan to use variables of structure types defined or call functions declared in the stdio.h file. What this does is basically provide forward declarations of these structure types and function calls so that the compiler does not throw the undefined reference errors for those structures and function calls. This is a requirement of the C language that all the functions, structure types and variables being used be declared before the usage.
In C, all lines starting with # are macros. A macro has a name and a value. The word following the # symbol is the name of the macro. Wherever this name is used in the following code, it'll be replaced by the value of the macro. For instance, in the above example, the name of the macro is "include" and it'll be replaced by the contents of the header file it is given as argument; in this case stdio.h. There are several such macros provided by the C language itself for our convenience.
Macros are processed before the compiler by a pre-processor. The pre-processor, replaces the macro line with the value of the macro.The output of the pre-processor is then consumed by the compiler. So at the pre-processor stage, many of the standard 'C rules' are not checked for. Obviously, if you set illegal code as the macro's value, it'll not be passed by the compiler. But then, if used correctly, it can be very beneficial.
Macro names
Any valid C identifier can be used as the name of a macro; even a C keyword. You cannot, however, use the "defined" keyword. This name is reserved and is used for checking if a macro name is already used. I'll cover this keyword in detail in the next part.Macro types
There are two types of macros. One that acts as a function and the one that acts just as a name for a piece of code; let's call it a non-function macro.Non-function macro:
This kind of macro is substituted entirely by it's content as it is. It's merely a name for a block of code which will be replacedDefining a non-function macro
To define a non-function macro, you simply use another macro named "define". Say we want to define a macro PI which when used in the code will be replaced by the value 3.14. We'll do it as follows# define PI 3.14
Wherever this macro is used in the following code, it'll be replaced by 3.14.
e.g. Consider a statement such as
int radius=2, circumference=2*PI*radius;
After preprocessing, the statement will look like
int radius=2, circumference=2*3.14*radius;
Another example would be, say if we wanted to have a short form for a piece of code that we want to use every now and then. For example, say the line
printf("This is line number %d in file %s\n",__LINE__,__FILE__);is used in may places in our code for debugging. Let's create a macro for this so that we don't have to type this every time.
# define DEBUG printf("This is line number %d in file %s\n",__LINE__,__FILE__);
After this, anywhere DEBUG is used, it will be replaced with printf("This is line number %d in file %s\n",__LINE__,__FILE__);
Function macros
This kind of macros are followed by the parantheses () and take arguments within those parantheses similar to functions and can operate on those arguments just like functions with the difference being that these macros don't need to declare the type of the arguments and there is no check within its body for the same.Defining a function macro
Say we need a macro that'll take two numbers and return the multiplication of the two numbers. Here we'd require to pass the numbers at runtime. In the non-function macro, everything in the macro value is available to the macro beforehand; constants or global variables.But in this case the values are not available until the program runs. For this, we'll define a function macro as follows.
#define MULTIPLY(x,y) ({x}*(y))The above macro when used in a statement as below
int product=MULTIPLY(2,3);will translate into following after the pre-processing
int product=((2)*(3));You may ask why the extra brackets surrounding individual arguments x and y in the macro value. Well to understand why consider the following case
int x=1,y=2,z=3,product=MULTIPLY(x+y,z)Since macros substitute the macto call with the macro value as it is, the above call without the parantheses around the arguments in the macro will result into the following translation
int x=1,y=2,z=3,product=x+y*z;
Inline functions in c++ is similar to macro functions in C. Just that the macros are processed by a preprocessor and inline functions are processed by a compiler. Know more here.
Multi line macros
There are times when your macro value does not fit in a single line or that the value looks good with indentation. To enable this, a \ character is appended before the line break. This character indicates that the macro value is not over yet and the following line needs to be considered in its value.Let's take an example. Say you want to write a function macro that swaps two integers and print the values. Here's how you'd do it in a single line.
#define swap(x,y) x^=y;y^=x;x^=y;printf("Swapped values are %d and %d\n",x,y);
We could split the above macro's value on multiple lines as below
#define swap(x,y) \
x^=y;\
y^=x;\
x^=y;\
printf("Swapped values are %d and %d\n",x,y);
Note that the last line does not have a \ character in the end. That marks the end of the macro value. But say if you were to add a \ character at the end and leave the next line blank it would work. But be careful about this and make sure you do not end the last line with the \ character.
No comments:
Post a Comment