What are expressions with side effects and why sho

2019-01-15 14:20发布

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?

3条回答
Bombasti
2楼-- · 2019-01-15 14:41

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)

查看更多
聊天终结者
3楼-- · 2019-01-15 14:42

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).

查看更多
Lonely孤独者°
4楼-- · 2019-01-15 15:05

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.

查看更多
登录 后发表回答