-1

I am newbie to C and trying to understand the MACRO expansion logic in C. I wonder why the first approach is not working but second works as expected.

First approach

#include <stdio.h>
#define square(x) x*x
int main()
{
    int x = 36/square(6); // Expended as 36/6*6
    printf("%d", x);
    return 0;
}
// Output: 36

Second approach

#include <stdio.h>
#define square(x) x*x
int main()
{
    int x = square(6)/36; // Expended as 6*6/36
    printf("%d", x);
    return 0;
}
// Output: 1

Could someone explain me the difference ?

Hipster1206
  • 411
  • 6
  • 13

4 Answers4

2
square(6)/36

expands to

6*6/36

which is equivalent to

(6*6)/36

and obviously equals 1.

Even though this is apparently for understanding macros and you may be aware of that, one suggestion:
macros involving operators should be surrounded by parantheses!

cadaniluk
  • 15,027
  • 2
  • 39
  • 67
  • 2
    Better still - Try to avoid them – Ed Heal Dec 12 '15 at 16:38
  • Yeah I know that...but why is the first approach not working ? i mean 36/6*6 – Hipster1206 Dec 12 '15 at 16:42
  • @kris_lazybum `36 / 6 = 6` and `6 * 6 = 36`. Evaluation order is left to right. – cadaniluk Dec 12 '15 at 16:54
  • 1
    @EdHeal In C, they might be needed sometimes for true constants and, in my personal opinion, they may be used in C. Not so in C++; IMO, they should have been banished a long time ago. – cadaniluk Dec 12 '15 at 16:58
  • @cad - That is why I said that they should be avoided. Using them as constants is fine. Trouble with macros is that they make the code difficult to debug. – Ed Heal Dec 12 '15 at 17:00
0

First expansion

36/6*6

Using the rules of precedence and left to right http://en.cppreference.com/w/c/language/operator_precedence works it out as

36/6 * 6 -> (36 / 6) * 6 -> 6 * 6  -> 36

Second expansion

6*6/36 -> (6 * 6)/36 -> 36 / 36 -> 1

Using the precedence/left to right rules above.

Sorry for the link - Did not want the cutter. Multiplication has higher precedence than division

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
0

Your macro should be defined as

#define square(x) ((x)*(x))

It is necessary to enclose the x's in parenthesis to prevent any surprises about operator precedence. The outer parenthesis are for the same reason.

Please note that this macro even as corrected above will not work if the parameter is a self-modifying expression. So you may want to consider putting it in all-uppercase or something to alert the user of the macro that it will not behave equivalently to a function call.

The reason your expansion of 36/square(6) does not work as you expect is because of its expansion.

36/square(6)
36/6*6
6*6  <-- 36/6 evaluated
36   <-- 6*6 evaluated

The corrected macro would be expanded thus

36/((6)*(6))
36/(36)
1

Which is the answer you would expect. Also note that 5+1 would also work as an argument because of the inner parenthesis but y++ would not behave as you would expect if reading the macro as a function, hence the reason I recommend naming it SQUARE to alert the user that this is a macro not a function.

Macros only behave as functions if each of their parameters appears exactly once and the syntax is otherwise like an expression (i.e. no {}'s). Also the user cannot pass a pointer to a macro as they can to a function.

Ken Clement
  • 748
  • 4
  • 13
0

Your question is a good illustration of the kind of problem that arise with macros:

36/square(6) expands to 36/6*6, which is parsed according to the C grammar as

(36 / 6) * 6

evaluating to 36.

If you had defined the macro as

#define square(x)  ((x)*(x))

Both expressions would be equivalent and evaluate to 1.

Yet there is still a problem with this macro:

square(i++) expands as ((i++) * (i++)).

Evaluating i++ twice in the same expression is undefined behavior.

chqrlie
  • 131,814
  • 10
  • 121
  • 189