Search code examples
cmacrosside-effects

What are expressions with side effects and why should they be not passed to a macro?


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?


Solution

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