4
#include<stdio.h>
#define CUBE(x) (x*x*x)

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

This code returns the value of a=150 and b=6. Please explain this.

I think when it executes the value of a will be calculated as a=4*5*6=120 but it isn't true according to the compiler , so please explain the logic....

NotMe
  • 87,343
  • 27
  • 171
  • 245

3 Answers3

9

There's no logic, it's undefined behavior because

++b * ++b * ++b;

modifies and reads b 3 times with no interleaving sequence points.

Bonus: You'll see another weird behavior if you try CUBE(1+2).

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

In addition to what Luchian Grigore said (which explains why you observe this weird behavior) you should notice that this macro is horrible: it can cause subtle and very difficult to track-down bugs, especially when called with a statement that has side-effects (like ++b) since this will cause the statement to execute multiple times.

You should learn three thing from this:

  1. Never reference a macro argument more than once in a macro. While there are exceptions to this rule, you should prefer to think of it as absolute.

  2. Try to avoid calling macros with statements that contain side-effects if possible.

  3. Try to avoid function-like macros when possible. Use inline functions instead.

NotMe
  • 87,343
  • 27
  • 171
  • 245
Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37
2

Its undefined behavior to change same variable more then once in a sequence. And because this reason you will get difference results with different compilers for your code.

By the chance I am also getting same result a = 150 and b = 6 with my compiler.

gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)

Your macro expression a = CUBE(++b); expanses as

a = ++b * ++b * ++b; 

And b is change more then once before end of full expression..

But how my compiler convert this expression at low level (may be your compiler do similarly and you can try with same technique). for this I compiled the source C with -S option and I got an assembly code.

gcc x.c -S

you will get x.s file.

I am showing partial useful asm code (read comments)

Because you want to know how does 150 output, thats why I am adding my answer

movq    %rsp, %rbp
.cfi_def_cfa_register 6
subq    $16, %rsp
movl    $3, -8(%rbp)    // b =  3 

addl    $1, -8(%rbp)    // b =  4
addl    $1, -8(%rbp)    // b =  5

movl    -8(%rbp), %eax  // eax = b  
imull   -8(%rbp), %eax  // 5*5 = 25

addl    $1, -8(%rbp)    // 6  `b` become 6 and

imull   -8(%rbp), %eax  // 6 * 25 = 150 
movl    %eax, -4(%rbp)  // 150 assign to `a` become 150 

movl    $.LC0, %eax     // printf function stuff...
movl    -8(%rbp), %edx
movl    -4(%rbp), %ecx
movl    %ecx, %esi
movq    %rax, %rdi  

On inspecting this assembly code I can understand it evaluate the expression like a = 5 * 5 * 6 thus a becomes 150 and after three increments b becomes 6.

Although different compilers produce different result but I think, 150 cab only be evaluated this sequence for b=3 and your expression in 5*5*6

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208