I came across a statement in the text C How to Program:
"Expressions with side effects (i.e., variable values are modified) should not be passed to a macro because macro arguments may be evaluated more than once.".
My question is what are expressions with side effects and why should they be not passed to a macro?
The classic example is a macro to calculate the maximum of two value:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Now lets "call" the macro like this:
int x = 5;
int y = 7;
int z = MAX(x++, y++);
Now if MAX
was a normal function, we would expect that x
and y
would be incremented once, right? However because it's a macro the "call" is replaced like this:
int z = ((x++) > (y++) ? (x++) : (y++));
As you see, the variable y
will be incremented twice, once in the condition and once as the end-result of the ternary operator.
This is the result of an expression with side-effects (the post-increment expression) and a macro expansion.
On a related note, there are also other dangers with macros. For example lets take this simple macro:
#define MUL_BY_TWO(x) (x * 2)
Looks simple right? But now what if we use it like this:
int result = MUL_BY_TWO(a + b);
That will expand like
int result = (a + b * 2);
And as you hopefully knows multiplication have higher precedence than addition, so the expression a + b * 2
is equivalent to a + (b * 2)
, probably not what was intended by the macro writer. That is why arguments to macros should be put inside their own parentheses:
#define MUL_BY_TWO(x) ((x) * 2)
Then the expansion will be
int result = ((a + b) * 2);
which is probably correct.
To put it simply a side effect is a write to an object or a read of a volatile object.
So an example of a side effect:
i++;
Here is a use of a side effect in a macro:
#define MAX(a, b) ((a) > (b)) ? (a) : (b))
int a = 42;
int b = 1;
int c;
c = MAX(a, b++);
The danger is contrary to a function where the arguments are passed by value you are potentially modifying b
object one or two times (depending on the macro arguments, here one time) in the macro because of the way macros work (by replacing the b++
tokens in the macro definition).
Side Effects can be defined as:
Evaluation of an expression produces something and if in addition there is a change in the state of the execution environment it is said that the expression (its evaluation) has some side effect(s).
For example:
int x = y++; //where y is also an int
In addition to the initialization operation the value of y gets changed due to the side effect of ++ operator.
Now consider a macro for squaring of an integers :
#define Sq(a) a*a
main()
{
int a=6;
int res=Sq(a);
printf("%d\n",res);
res=Sq(++a);
printf("%d",res);
}
You would expect the output to be
36
49
However the output is
36
64
because macro results in textual replacement and
res becomes (++a)*(++a)
i.e, 8*8=64
Therefore we should not pass arguments with side effects to macros.
(http://ideone.com/mMPQLP)