How does macro expansion work in below code? [duplicate] - c

This question already has answers here:
Why is "i" variable getting incremented twice in my program?
(8 answers)
Closed 6 years ago.
In the code below, according to me, the output should be 11 6 10, but it gives 12 6 11. The value of k=x as returned by the ternary operator since x>y where x=10 and y=6, so i=11, j=6 and k=10, so why is there a mismatch in the output produced?
#include <stdio.h>
#define MAX(x,y)(x)>(y)?(x):(y)
int main()
{
int i=10,j=5,k=0;
k=MAX(i++,++j);
printf("%d %d %d",i,j,k);
return 0;
}

The expansion is equivalent to:
k = (i++) > (++j) ? (i++) : (++j);
Both i and j are incremented as the condition is evaluated (so i becomes 11 and j becomes 6. Since the condition checks the original value of i and the incremented value of j and 10 > 6, the i++ after the ? is evaluated, so k is assigned 11 and i is incremented to 12.
Hence the output is, as it should be:
12 6 11
There is no undefined behaviour here. There's a full sequence point after the condition is evaluated.
Note, too, that for full safety, the macro should have an extra set of parentheses around the expansion:
#define MAX(x,y) ((x) > (y) ? (x) : (y))
Otherwise, you get odd-ball effects from:
int l = 7 * MAX(k, i) + 3;
It works; it just doesn't work as expected.

The output works as expected. You'll need to understand macros are expanded, and do not work like functions where the input parameters are copied.
The definition of MAX in the above code is
#define MAX(x, y) (x)>(y)?(x):(y)
So
k = MAX(i++, ++j)
expands to
k = (i++)>(++j)?(i++):(++j)
The variable i gets incremented twice when i=10 and j=5. The variable j gets incremented only once.
So eventually i=12 and j=6, and k=11 because the second operand in the ternary operator is a post-increment.
If you are using gcc, running cpp instead of gcc on the .c file would expand the macro nicely for you.
Apart from Jonathan Leffler's comment on using more parentheses in the macro for safety, you can consider using inline functions that could save you from these unintended results. Inline functions have the benefits of being typed, passing-by-value, and code expansion.
inline int max(int x, int y) { return x > y ? x : y; }
See the wiki for more details.

Related

Does macro function with operator precedence show unusual result?

#define SQUARE(x,y) (x<y?x:y)
int a = 5, b = 6, c = 3;
int var = SQUARE(a & c,b);
I have searched and learnt that '<' precede '&'. As per rules it should give '5'. But it is giving output as '1'. But in some cases it is giving right output. Can you please explain macro rules of this and what am I missing here.
Macros are just replaced by the preprocessor, so the arguments are not evaluated and then passed like in functions.
In your example the expression SQUARE(a & c, b); will become (a & c < b ? a & c : b);
For a=5, b=6, c=3 it evaluates to:
(5 & 3<6 ? 5&3 : 6) //'<' precede '&' as you correctly mentioned
(5&1 ? 5&3 : 6) // '3 < 6' is a boolean expression which evaluates to 1. '&' is bitwise AND.
(1 ? 1 : 6)
(1)
So 1 is the right output.
EDIT:
A good aproach is to always use parentheses around your arguments and the whole expression to eliminate the problem of operator precedence.
As mention by others it can be dangerous to use macros due to multiple evaluation, which may not only effect performance.
For example:
#define SQUARE(x) ((x)*(x))
seems to only square the argument, but if you call it like
f = SQUARE(x++);
you will get undefined behaviour. A better approach for small function would be to declare it as inline.
inline int square(int x)
{
return x*x;
}
Also as mentioned by #EricPostpischil macros are not a textual replacement as the preprocessor replaces by tokens.
For example:
#define a 1
#define b 2
printf("%d\n", ab);
here ab is not replaced with 12 as someone would expect for pure textual replacement.
Macros require parentheses as they are not functions and just do the textual replacement
#define SQUARE(x,y) (((x)<(y))?(x):(y))
The macro is extremely side effects error and UB prone:
Example: SQUATE(x++,y)
in your example 5 & 3 will be evaluated every time you have the x in your macro. It will be less effective than the inline function
inline unsigned SQUARE(unsigned x, unsigned y)
{
return (x < y) ? x : y;
}
In a bit more detail, as #P__J__ said, macros are just text replacement by the pre-processor, not functions. So this:
#define SQUARE(x,y) (x<y?x:y)
int a = 5, b = 6, c = 3;
int var = SQUARE(a & c,b);
is translated to:
int a = 5, b = 6, c = 3;
int var = (a & c<b?a & c:b);
Because every x is replaced with a & c and every y is replaced with b.
If you also apply the values as in #Osiris 's answer, you'll get:
int var = (5 & 3 < 6 ? 5 & 3 : 6);
At this point, as you already said, < takes precedence over &.
The result of < is true or false, which means 1 or 0, so 3 < 6 becomes 1.
The result of & is the bitwise AND between two numbers, which in this case is also 1 (because 5 is 101 and 3 is 011).
This is why it becomes
(5 & 1 ? 1 : 6)
That next 5 & 1 will also become 1 (because of the AND between 101 and 001), so you'll get:
(1 ? 1 : 6)
And since 1 is true, you'll get the first value, which is also a 1.
Also, as already pointed out, be careful with evaluation in a macro.
These are just numbers and you're already seeing some not so obvious behaviour, but if had passed a function as one of the arguments, that function would've run multiple times.
For example
#define SQUARE(x,y) (x<y?x:y)
int var = SQUARE(update_counter(a), 1);
would have been translated to
int var = (update_counter(a) < 1 ? update_counter(a) : 1);
Thus potentially updating a hypothetical counter twice.

execution of ternary operator

#include <stdio.h>
#define max(x,y)(x)>(y)?x:y
int main() {
int i = 10;
int j = 5;
int k = 0;
k == max(i++, ++j);
printf("%d%d%d ", i, j, k);
return 0;
}
I know the answer. It is 11 7 0 but how? please help me with the execution of the ternary operator.
The statement
k==max(i++,++j);
is expanded to
k==(i++)>(j++)?i++:j++;
Note that == has higher precedence than ?: operator and therefore the above expression is equivalent to
( k == ((i++)>(j++)) )?i++:j++;
Since (i++)>(j++) will be true, therefore k == ((i++)>(j++)) is evaluated as false and hence j++ (and it's value become 7) will be evaluated (i++ will be skipped).
NOTE: The above expression does not invoke undefined behavior because there exists sequence point between the evaluation of the first operand of the ternary operator and the second or third operand. For example, the expression
a = (*p++) ? (*p++) : 0
has well defined behavior.
This question is definitely a trick question that will catch many unsuspecting C programmers. The different responders here have more than 100 years of compounded experience in C, yet it took several tries to get this right:
The expression k == max(i++, ++j); expands to:
k == (i++)>(++j)?i++:++j;
Which is parsed as this (== has lower precedence than >, but higher precedence than ?):
(k == ((i++) > (++j)))
? i++
: ++j;
The ternary operator evaluates the test (i++)>(++j), which is true for the values in the program, hence evaluates to 1, different from the value of k, so it proceeds to evaluate the third expression j++, which increments j a second time and returns the intermediary value 6. There is a sequence point between the test and the branch that is executed, so it is OK to increment j twice. The second branch is not executed at all since the test evaluated to false.
i is incremented once, its value becomes 11.
j is incremented twice, its value is 7.
k is not modified by the above statement, because == is the comparison operator, not the assignment operator.
Hence the output is 11 7 0
Notes:
The program uses a macro max that evaluates its arguments more than once and they are not properly parenthesized in the expansion: 2 errors that illustrate the shortcomings of macros. This macro should be names MAX to emphasize the fact that its arguments should not have side effects and its expansion should be fully parenthesized this way:
#define MAX(x,y) ((x) > (y) ? (x) : (y))
A better alternative is to make it an inline function:
static inline int max(int x, int y) {
return x > y ? x : y;
}
If the program had this statement:
k = max(i++, ++j);
The output would be 12 6 11 because unlike ==, = has lower precedence than ? so the statement would expand to:
k = ((i++) > (++j))
? i++
: ++j;
You can study the table of operator precedence for C. There are in my humble opinion too many levels and it is very difficult to memorize all of them, especially since some of them are rather counter-intuitive: print a copy and keep it handy or make a bookmark. When in doubt, use parentheses.
You're using a double equal sign, which is a comparison. k==max(i++,++j); compares the return value of max to k, which is 0.
Instead, try changing the == to =.

Macro usage in C?

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 ?
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!
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
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.
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.

operator ++ applied two times, depending on arguments to #define function [duplicate]

This question already has answers here:
Problem with Macros
(4 answers)
Closed 9 years ago.
On the snipet below, the operator ++ is called two times.
Why ??
#define CALL_WITH_MAX(a,b) ((a) > (b) ? (a) : (b))
int main()
{
int a = 5, b =0;
CALL_WITH_MAX(++a,b);
// a was incremented by one two times !!!!
CALL_WITH_MAX(++a,b+10);
//a incremented as expected...
return 0;
}
CALL_WITH_MAX(++a,b)
expands to
((++a) > (b) ? (++a) : (b))
^ ^ //A is incremented twice when ++a < b
++a = 6 and b = 0
6 > 0 == true
++a is returned => ++a = 7
In your second option
++a = 6 and b = 0 + 10 = 10
6 > 10 == false.
This time just b is returned.
Because argument is taken as is - without extracting variable names, etc. That's what it becomes:
((++a) > (b) ? (++a) : (b));
As incremented a is greater than b, the second part of ternary expression will be evaluated as well.
In the second case, however, the clause is falsy: 6 is less than 10. That's why third part of the ternary is evaluated instead, and a will be incremented just once.
If the first argument is larger than the second, it is evaluated 2 times.
Therefore in the first case you have:
(++a) > (b) ? (++a) : (b)
and since (++a) > (b) you get (++a), which increments a once more.
If you expand the macro it will become like
((++a) > (b) ? (++a) : (b))
6 > 0 then a is again incremented.
The macro expands to:
((++a) > (b) ? (++a) : (b))
vs.
((++a) > (b+10) ? (++a) : (b+10))
in the former, ++a is evaluated twice
The macro is not "compiled", it's completely different from writing a function you run during the execution of your application. Treat a macro as something that helps you write your code, not perform calculations.
Therefore
CALL_WITH_MAX(++a,b)
will generate
((++a) > (b) ? (++a) : (b));
which then is "read" by the compiler and compiled to actual code. This means that a will be incremented twice, because b is smaller than a, and therefore the (++a) is run. If b is larger, then the second (++a) is not executed and only b is returned.
This is why macros are also known as preprocessor directives, because they are used in the preprocessing phase of the build process. The values of the variables are not read or changed, the directive just reads the text you provide it with and generates code for you.
If you look at macros that already exist like __LINE__, it will return the line number for you in your code; however it will literally insert it as part of your code, it will not be a function that is run during the execution of your application. Similarly the macro __TIME__ will not return the current time but the time of when the compilation process was started.
I hope this will help you to change your approach to macros and how they work.
Most of the answers on this questions are correct. Here is a typical fix for the issue:
#define CALL_WITH_MAX(a,b) ({ typeof(a) _a=a; typeof(b) _b=b; ((_a) > (_b) ? (_a) : (_b)); })
Works with gcc.
Basically, it creates a copy of a & b, with same data types & operates on these copies.
The only time a gets incremented is at _a=a; statement in macro.
You can test the expansion with -E flag to gcc; like gcc -E test_macro.c ...
The prefixed increment operator has higher order of procedure so the value of the variable is increased by 1 before evaluation .
you call your function with arguments (++a,b) so you need to replace all the variable with this passed value so the function can be expressed as
`CALL_WITH_MAX(a,b) ((a) > (b) ? (a) : (b))
CALL_WITH_MAX(++a,b); `
so if you replace all a by ++a and b and b then your function can be expressed as
((++a) > (b) ? (++a) : (b))
the value of a is incremented by 1 before evaluation ..
I noticed in your code, you chose to name the macro's parameters a and b, which is also the name you used for your variables within your main function.
In my opinion, the problem you're having here is you probably think by naming them the same that they're linked somehow.. which is simply not true.
The parameters names in the macro don't tie them to variables of the same name in the program, they’re replaced by what you pass in. You might find this easier to see if we change the names a bit:
#define CALL_WITH_MAX(x,y) ((x) > (y) ? (x) : (y))
Then in your main program:
int a = 5, b =0;
CALL_WITH_MAX(++a,b);
Now you can see that x is replaced with ++a and y will be replaced by b. So the logic of your macro becomes:
if x > y then return x else return y
if ++a > b then return ++a else return b
if 6 > 0 then return 7 else return 0
So obviously 6 is greater than 0, so you increment again and return the value.
// a = 7; b = 0
CALL_WITH_MAX(++a,b+10);
So again, the same logic:
if x > y then return x else return y
if ++a > b then return ++a else return b
if 8 > 10 then return 9 else return 10
In this case 8 is not greater than 10, so we don't increment to 9, we just return 10. Thus after the first call to your macro a was incremented twice and after the second call a was only incremented once; hope that made it clearer.

Why doesn't this math work with macros? [duplicate]

This question already has answers here:
some error in output in using macro in C
(3 answers)
Closed 9 years ago.
Why doesn't this math work with macros in C?
#include <stdio.h>
#define FOO 6
#define BAR 32
#define MULT FOO * BAR
main() {
int x = 28296;
int y = x / MULT;
printf("%d / %d = %d\n", x, MULT, y);
return 0;
}
The result of this is:
28296 / 192 = 150912
Why isn't it 147? If I set a variable " int mult" equal to MULT, and use the variable in the expression (int y = x / mult) it works as expected.
#define tells the preprocessor to replace the code before compilation, so your line actually says:
int y = x / 6 * 32;
since * and / operators have the same precedence, and are evaluated from left to right, you get (x/6) * 32. The compiler would probably do this calculation for you since x is known to it.
Instead, use parenthesis when defining macros like this
Put a bracket around the macro:
#define MULT (FOO * BAR)
Now, you'll get 147.
The reason getting 150912 is that after macro expansion the expression is equivalent to:
y = 28296 / 6 * 32;
and hence it's evaluated as 28296/6 and then multiplied by32.
As #kevin points out, it's better to put brackets around FOO and BAR as well in general case to avoid surprises like this.

Resources