I was doing some exercises online and I was given this code:
#include <stdio.h>
#define CUSTOM_ADD(x) ++x+++x
int main() {
int a=6;
int b=8;
printf("%d",a + CUSTOM_ADD(a+b)+b);
return 0;
}
I figured out that the addition a+b(14) is passed on the macro and it opens like that ++14+ ++14 =30 then the final result should be 44. I also considered that the macro might expand like that: ++14++ +14 Which would be 29, since the value would be incremented after the usage and the final result could be 43. I was not sure which one would be right, so I ran the code and the output was 47. I just could not find anyway to reach the result.
Macro processing works by replacing grammatical tokens.
In
#define CUSTOM_ADD(x) ++x+++x, the replacement list is parsed to the tokens++x+++x. When determining the next token, the rule is to take the longest sequence of characters that could constitute a token, so analyzing+++produces++first, then+.In
printf("%d",a + CUSTOM_ADD(a+b)+b);, macro replacement results inprintf("%d",a + ++ a + b ++ + a + b + b);.The second argument to
printfis parsed asa + (++a) + (b++) + a + b + b. The behavior of this code is not defined by the C standard because it both modifiesa, in++a, and uses the value ofawithout sequencing between them. The same problem exists withb++andb.In ordinary modern C implementations, it is not uncommon that the above expression would produce a value of
a+a+a+b+b+bas ifaandbhad been incremented somewhere in the sequence of additions, withaincremented at least once before its last use. Thus, withastarting at 6 andbstarting at 8, it could produce 42 (6+6+7+8+8+8, withaincremented after the first addition of 6+6 andbincremented after all of them) or 48 (7+7+7+9+9+9) or anything in between. However, another potential result is that compiler analysis determines the behavior of the code is not defined by the C standard, and therefore a well-written program would never transfer program control to this execution path, so it may be removed from the program entirely.One reason the rule exists is that, for some types, updating a variable requires multiple operations, such as for wide integers implemented using multiple operations on small processors. And a compiler could not always tell whether an expression was both updating a variable and using the same variable, as when a pointer is used. For example, in
++*p + *q, the compiler generally does not know whetherpandqpoint to the same thing. If they did, and multiple steps are needed to increment the variable, the compiler could generate instructions that are incrementing*pinterleaved with instructions that are fetching its value for*q. The C standard committee decided to put the onus on programmers to avoid this.