41

I tried to play with the definition of the macro SQR in the following code:

#define SQR(x) (x*x)
int main()
{
    int a, b=3;
    a = SQR(b+5);      // Ideally should be replaced with (3+5*5+3), though not sure.
    printf("%d\n",a);
    return 0;
}

It prints 23. If I change the macro definition to SQR(x) ((x)*(x)) then the output is as expected, 64. I know that a call to a macro in C replaces the call with the definition of the macro, but I still can’t understand, how it calculated 23.

Palec
  • 12,743
  • 8
  • 69
  • 138
Kushal
  • 3,112
  • 10
  • 50
  • 79
  • 3
    In your future career. Try not to rely on macro's at all. Or if you do have to use them, use them for very small bits of code. Not huge macro monstrosities that cover half a page. – C.J. May 30 '12 at 16:30
  • @CJohnson: Yes, I've hardly realized the need of using a Macro in my C/C++ projects, this is one of those confusing areas of C, even after being a developer/student for years. – Kushal May 30 '12 at 16:42
  • 2
    Related: [Can we remove parentheses around arguments in C macros definitions?](http://stackoverflow.com/q/27752386/2157640) – Palec Apr 29 '15 at 08:51
  • 2
    Related: [When can the parentheses around arguments in macros be omitted?](http://stackoverflow.com/q/20964369/2157640) – Palec Apr 29 '15 at 09:43
  • [Nice answer to a duplicate](http://stackoverflow.com/a/7186517/2157640) – Palec Apr 29 '15 at 09:58

8 Answers8

43

Pre-processor macros perform text-replacement before the code is compiled so SQR(b+5) translates to (b+5*b+5) = (6b+5) = 6*3+5 = 23

Regular function calls would calculate the value of the parameter (b+3) before passing it to the function, but since a macro is pre-compiled replacement, the algebraic order of operations becomes very important.

Babak Naffas
  • 12,395
  • 3
  • 34
  • 49
18

Consider the macro replacement using this macro:

#define SQR(x) (x*x)

Using b+5 as the argument. Do the replacement yourself. In your code, SQR(b+5) will become: (b+5*b+5), or (3+5*3+5). Now remember your operator precedence rules: * before +. So this is evaluated as: (3+15+5), or 23.

The second version of the macro:

#define SQR(x) ((x) * (x))

Is correct, because you're using the parens to sheild your macro arguments from the effects of operator precedence.

This page explaining operator preference for C has a nice chart. Here's the relevant section of the C11 reference document.

The thing to remember here is that you should get in the habit of always shielding any arguments in your macros, using parens.

pb2q
  • 58,613
  • 19
  • 146
  • 147
11

Because (3+5*3+5 == 23).

Whereas ((3+5)*(3+5)) == 64.

The best way to do this is not to use a macro:

inline int SQR(int x) { return x*x; }

Or simply write x*x.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
8

The macro expands to

 a = b+5*b+5;

i.e.

 a = b + (5*b) + 5;

So 23.

Mat
  • 202,337
  • 40
  • 393
  • 406
4

After preprocessing, SQR(b+5) will be expanded to (b+5*b+5). This is obviously not correct.

There are two common errors in the definition of SQR:

  1. do not enclose arguments of macro in parentheses in the macro body, so if those arguments are expressions, operators with different precedences in those expressions may cause problem. Here is a version that fixed this problem

    #define SQR(x) ((x)*(x))
    
  2. evaluate arguments of macro more than once, so if those arguments are expressions that have side effect, those side effect could be taken more than once. For example, consider the result of SQR(++x).

    By using GCC typeof extension, this problem can be fixed like this

    #define SQR(x) ({ typeof (x) _x = (x); _x * _x; })
    

Both of these problems could be fixed by replacing that macro with an inline function

   inline int SQR(x) { return x * x; }

This requires GCC inline extension or C99, See 6.40 An Inline Function is As Fast As a Macro.

Lee Duhem
  • 14,695
  • 3
  • 29
  • 47
2

A macro is just a straight text substitution. After preprocessing, your code looks like:

int main()
{
    int a, b=3;
    a = b+5*b+5;
    printf("%d\n",a);
    return 0;
}

Multiplication has a higher operator precedence than addition, so it's done before the two additions when calculating the value for a. Adding parentheses to your macro definition fixes the problem by making it:

int main()
{
    int a, b=3;
    a = (b+5)*(b+5);
    printf("%d\n",a);
    return 0;
}

The parenthesized operations are evaluated before the multiplication, so the additions happen first now, and you get the a = 64 result that you expect.

Caleb
  • 124,013
  • 19
  • 183
  • 272
1

Because Macros are just string replacement and it is happens before the completion process. The compiler will not have the chance to see the Macro variable and its value. For example: If a macro is defined as

#define BAD_SQUARE(x)  x * x 

and called like this

BAD_SQUARE(2+1) 

the compiler will see this

2 + 1 * 2 + 1

which will result in, maybe, unexpected result of

5

To correct this behavior, you should always surround the macro-variables with parenthesis, such as

#define GOOD_SQUARE(x)  (x) * (x) 

when this macro is called, for example ,like this

GOOD_SQUARE(2+1)

the compiler will see this

(2 + 1) * (2 + 1)

which will result in

9

Additionally, Here is a full example to further illustrate the point

#include <stdio.h>

#define BAD_SQUARE(x)  x * x 
// In macros alsways srround the variables with parenthesis
#define GOOD_SQUARE(x)  (x) * (x) 

int main(int argc, char const *argv[])
{
    printf("BAD_SQUARE(2) = : %d \n", BAD_SQUARE(2) ); 
    printf("GOOD_SQUARE(2) = : %d \n", GOOD_SQUARE(2) ); 
    printf("BAD_SQUARE(2+1) = : %d ; because the macro will be \
subsituted as 2 + 1 * 2 + 1 \n", BAD_SQUARE(2+1) ); 
    printf("GOOD_SQUARE(2+1) = : %d ; because the macro will be \
subsituted as (2 + 1) * (2 + 1) \n", GOOD_SQUARE(2+1) ); 

    return 0;
}
Amjad
  • 3,110
  • 2
  • 20
  • 19
-3

Just enclose each and every argument in the macro expansion into parentheses.

#define SQR(x) ((x)*(x))

This will work for whatever argument or value you pass.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Nikhil Goyal
  • 576
  • 4
  • 11
  • 3
    No explanation, no answer to the question (*how* macros expansion works), wrong formatting, no added value. Therefore no reason to exist for this answer. – Palec Mar 13 '16 at 15:11