Here\'s some more weird macro behavior I was hoping somebody could shed light on:
#define MAX(a,b) (a>b?a:b)
void main(void)
{
int a = 3, b=4;
print
There are two reasons for the result that you're getting here:
A macro is nothing but code that is expanded and pasted when you compile. So your macro
MAX(a,b) (a>b?a:b)
becomes this
a++>b++?a++:b++
and your resulting functions is this:
printf("%d %d %d\n",a,b, a++>b++?a++:b++);
Now it should be clear why b is incremented twice: first in comparison, second when returning it. This is not undefined behaviour, it is well defined, just analyse the code and you'll see what exactly to expect. (it is predictable in a way)
The second problem here is that in C parameters are passed from last to first to the stack, hence all the incrementation will be done before you print the original values of a and b, even if they're listed first. Try this line of code and you'll understand what I mean:
int main(void)
{
int a = 3, b=4;
printf("%d %d %d\n",a,b, b++);
return 0;
}
The output will be 3 5 4.
I hope this explains the behaviour and will help you to predict the result.
BUT, the last point depends in your compiler
So your expansion gives (adjusted for clarity):
(a++ > b++) ? a++ : b++
... so (a++ > b++)
is evaluated first, giving one increment each and selecting a branch based on the not-yet-incremented values of a
and b
. The 'else' expression is chosen, b++
, which does the second increment on b
, which was already incremented in the test expression. Since it's a post-increment, the value of b
before the second increment is given to printf()
.
Macros are evaluated by the preprocessor which stupidly replaces all according to the macro definitions. In your case, MAX(a++, b++)
becomes (a++>b++) ? a++ : b++
.
If i'm correct, this is happening:
with MAX replaced with (a>b...) you have printf("%d %d %d\n",a,b,(a++ > b++ ? a++ : b++ ) );
First, a++ > b++ is checked and both values increased (a = 4, b = 5) afterwards. Then the second b++ gets active, but because it's postincrement, it's increased after the second value b = 5 is printed.
Sorry for my bad english, but i hope you understand it?! :D
Greeings from Germany ;-)
Ralf
Macros do text substitution. Your code is equivalent to:
printf("%d %d %d\n",a,b, a++ > b++ ? a++ : b++);
This has undefined behavior, because b
is potentially incremented (at the end of the third argument) and then used (in the second argument) without an intervening sequence point.
But as with any UB, if you stare at it for a while you might be able to come up with an explanation of what your implementation has actually done to yield the result you see. Order of evaluation of arguments is unspecified, but it looks to me as though the arguments have been evaluated in right-to-left order. So first, a
and b
are incremented once. a
is not greater than b
, so b
is incremented again and the result of the conditional expression is 5
(that is to say, b
after the first increment and before the second).
This behavior is not reliable - another implementation or the same implementation on another day might give different results due to evaluating the arguments in a different order, or theoretically might even crash because of the sequence point issue.
In macro, parameters are just replaced by the arguments; so arguments can be evaluated multiple times if they are present multiple times in the macro.
Your example:
MAX(a++,b++)
Expands to this:
a++>b++?a++:b++
I think you don't need more explanations :)
You can prevent this by assigning each parameter to a temporary variable:
#define MAX(a,b) ({ \
typeof(a) _a = a; \
typeof(b) _b = b; \
a > b ? a : b; \
})
(This one uses several GCC extensions, though)
Or use inline functions:
int MAX(int a, int b) {
return a > b ? a : b;
}
This will be as good as a macro at runtime.
Or don't do the increments in the macro arguments:
a++;
b++;
MAX(a, b)