I am trying to learn the basics of C/C++ right now. I am going through a course on Lynda.com
My questions deals with a sequence of code from Chapter 4 "Macro caveats from the Course C/C++ Essential Training". I have followed all the setup procedures to get Xcode and Eclipse setup correctly on a Mac and Eclipse on a PC. When I run this code on a MAC and PC I get different results. Just trying to understand why that is happening and what I can do to get the same result on both.
Here is the code:
// working.c by Bill Weinman <http://bw.org/>
#include <stdio.h>
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
int increment() {
static int i = 42;
i += 5;
printf("increment returns %d\n", i);
return i;
}
int main( int argc, char ** argv ) {
int x = 50;
printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment()));
printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment()));
return 0;
}
On a PC I get this result:
increment returns 47
increment returns 52
max of 50 and 52 is 50
increment returns 57
increment returns 62
increment returns 67
max of 50 and 67 is 62
On a MAC (both Xcode and Eclipse) I get this result:
increment returns 47
increment returns 52
increment returns 57
max of 50 and 47 is 57
increment returns 62
increment returns 67
increment returns 72
max of 50 and 62 is 72
Why is this happening and what can I do to make sure the results are the same?
Intentional duplicates are files that you've created multiple backups or need to have saved in different folders. But because those files have the same name, any app would see them as unwanted files. Accidental duplicates are files that you've maybe downloaded multiple times or didn't mean to save in various locations.
Due to user errors, repetitive imports, or bugs, you might have multiple copies of images in your Mac's Photos app.
You have unspecified results here.
Order of evaluation within printf()
is not defined.
Once you have multiple increment()
calls within the same printf then you never know which once gets executed first and how they are evaluated.
The order in which all elements in a full-expression get evaluated is not defined. All that is required is that each sub-expression have its operands fully evaluated before it is evaluated. In the case of a function call, the arguments can be evaluated in any order, and in fact one argument might only be partially evaluated at the moment another argument becomes fully evaluated.
First, let's expand the macro:
printf("max of %d and %d is %d\n", x,
increment(),
((x) > (increment()) ? (x) : (increment()));
(Oops, there is another problem here: if increment()
is larger than x
then it gets called again. Make the MAX
macro a function instead so the arguments are only evaluated once!)
All of the following sequences are possible. I omit the evaluation of x
here because it doesn't change.
increment()
is evaluated, followed by x > increment()
, finally followed by whichever ?:
operand is selected. (This is likely the sequence you were expecting.)x > increment()
is evaluated, followed by whichever ?:
operand is selected, finally followed by the second argument increment()
.x > increment()
is evaluated, followed by the second argument increment()
, finally followed by whichever ?:
operand is selected.These may all yield different results, and they are all a correct interpretation of your code.
When you call multiple functions in a single full-expression, you should ensure that these functions either don't have any side-effects, or that the side-effects of each function do not change the behavior of any of the other functions. Otherwise, compiling on a different compiler (or a different version of the same compiler!) could change the result.
As an additional example, even the simple-looking expression increment() > increment()
has an unspecified result, because the order in which the operands are evaluated is not defined; if the left operand is evaluated first then the result will be false, otherwise it will be true.
In the more complicated example ((a + b) * (c + d))
the compiler can evaluate a
, b
, c
, and d
in any order that it pleases. All that is required is that a
and b
must be evaluated before a + b
can be, c
and d
must be evaluated before c + d
can be, and a + b
and c + d
must be evaluated before the final operator *
can be.
There are two problems here.
You are relying on whatever the compiler chooses for evaluating the arguments to printf(). The statements evaluated first modify the values of later statements. Move the increment() calls out of the argument list. Store the results of increment() in variables instead and pass those variables to printf().
Also, the macro expansion of MAX can cause either argument to be evaluated once or twice. So even on the same OS and compiler, you can get awkward results. To fix this, do the same as I suggested for storing the increment() results. Pass those variables to MAX().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With