Here is my function:
void abc(char *def, unsigned int w, unsigned int x, unsigned int y, unsigned int z)
{
printf("val 1 : %d\n", w);
printf("val 2 : %d\n", x);
printf("val 3 : %d\n", y);
printf("val 4 : %d\n", z);
}
and here is where I call this function:
unsigned int exp[4] = { 1, 2, 3, 4 };
unsigned short count = 0;
abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]);
and here is the output that I expect:
val1 : 1
val2 : 2
val3 : 3
val4 : 4
but what I get is completely reverse of it:
val1 : 4
val2 : 3
val3 : 2
val4 : 1
I don't know why? Any help would be appreciated.
From standard docs, 5.4
Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions,
and the order in which side effects take place, is unspecified58) Between the previous and next sequence point a
scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior
value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for
each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.
An example from the Standard docs itself,
i = v[i ++]; / / the behavior is undefined
And it is for the very same reason that
abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]); is undefined..
You should not use the ++ operator, operating on the same variable, more than once in the same statement. The order in which the operation will be performed is not defined.
Try:
abc(anyarray, exp[count], exp[count+1], exp[count+2], exp[count+3]);
count += 4;
You've invoked undefined behavior, by modifying count more than once without an intervening sequence point.
You are counting on the parameters being evaluated left to right. You can't make any assumptions about the order that they're evaluated. In this case, it looks like the compiler is evaluating them right-to-left.
Also, you may want to look up sequence points, because it may be that you shouldn't use the ++ operator in this way.
abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]);
The order of evaluation of arguments of abc is unspecified but the expression invokes undefined behaviour because you are trying to modify a variable count more than once between two sequence points.
Furthermore using incorrect format specifier in printf() also invokes UB. Please make sure you have used correct format specifiers(i.e %u for unsigned int) in printf().
You got this because you called adb(exp,a,b,c,d) according to your problem, but during call of function d is pushed first on stack and then c ,b relatively. As you passed exp[count++] at last argument which will process first to push over stack means 1 is pushed first then 2 then 3 then 4. And in called function pop performed so you get w=4 x=3 y=2 z=1 that's it.
This is because of the calling convention. In _cdecl, the default calling convention for c/c++ programs (according to microsoft), the parameters are passed on the stack to the function in reverse order. Because of this, the parameters are also evaluated in reverse order.
Related
This question already has an answer here:
Use pass by reference in recursion
(1 answer)
Closed 1 year ago.
I came across the following question:
#include <stdio.h>
int f(int &x, int c)
{
c = c - 1;
if (c == 0) return 1;
x = x + 1;
return f(x, c) * x;
}
int main()
{
int p = 5;
printf("%d", f(p, p));
}
As far as I have worked out, the recursion calls should work, and with each recursion call, value of c should reduce by 1 and value of x should increase by 1 . However, if I calculate it that way, the answer comes out to be 3024. However, on executing, the output comes out to be 6561. I am not really sure how this answer is coming.
I have the link to the article from where this question is taken, but I fail to understand how x will remain constant as is described in this link: https://www.geeksforgeeks.org/c-references-question-1/
Can someone help me with the working behind this code?
There can be any result, due to Undefined behavior.
Since the x is passed by reference, the last assign will matter. Thus, we have:
9*9*9*9*1=6561
We delay the evaluation of the f(x, c) * x, where all the subsequent recursive calls will have access to the x. We increment the x this way until the c is equal to 0, means we increment the x up to it being 9.
When we hit the base case (the c == 0), the current call returns 1, while the x is already 9.
Then we evaluate the multiplication 1 * x * x * x * x, where x is equal to 9. Thus, the 6561.
Flawless explanation? Not so much.
The fun part is that there is no concept of left-to-right or right-to-left evaluation in C++:
Order of evaluation of any part of any expression, including order of
evaluation of function arguments is unspecified (with some exceptions
listed below). The compiler can evaluate operands and other
subexpressions in any order, and may choose another order when the
same expression is evaluated again.
Means, that though this logic gets a pass this time, it may won't be this way next time for me or if you run it yourself.
int f(int &x, int c)
{
c = c - 1;
if (c == 0) return 1;
x = x + 1;
return f(x, c) * x;
}
int x = 5;
cout << f(x,5);
In the example above the four possible answers to choose from are:
3024
6561
55440
161051
Function f(int &x, int c) is called four times after the first call before it reaches the base case where it returns the result which is 6561. My guess was 3024 but I was wrong. Even if the x variable which is passed by reference increments in each call of f(int &x, int c) and takes the values 6->7->8->9 respectively the final result of this recursion is equal to 9^4.
So my question is: Variable x is passed by reference and is equal to 9 when it reaches the base case. Does that mean that all the stages of recursion will have this value for variable x even if they had a different value when they've been called?
No, there are more than four answers to choose from.
The fetch of x for the recursive function call, and the fetch of x for the right hand side of multiplication, is not sequenced with each other; and as such the evaluation order is unspecified.
This doesn't mean that the evaluation order would be some particular evaluation order, and it's only necessary to figure it out. This means that the final results can:
Vary depending on the compiler.
Vary each time this program executes.
The evaluation order may also be different for each individual recursive call. Each recursive call can end up using a different evaluation order, too. "Unspecified" means "unspecified". Any possibility can happen. Each individual time.
I didn't bother to calculate all actual possibilities here. It's better to invest one's own time on something that should work properly, instead of on something that obviously can never work properly.
If you want a specific evaluation order, it's going to be either this:
int y=x;
return f(x, c) * y;
Or this:
int y=f(x, c);
return y * x;
This evaluation order is now specified.
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 8 years ago.
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?
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.
The second argument 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().
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
Undefined Behavior and Sequence Points
Ok we all know that i++ increments value by 1 on next line and ++i increments on same line(please correct me if i am wrong there ) so for a sample statement of c as follows:
int a=0;
printf("%d , %d",++a,a);
the expected output should be 1 , 1 but instead it gives 1 , 0
so as one might guess what i am asking here is why does the second linking of
i print 0 instead of 1 when the value is already incremented.
So if post increment didn't increment value in the same line then what is the
difference between post and pre increment? edit : changed the name of variable from i to a to avoid grammatical confusion.
You are very wrong in your understanding of the increment operators.
i++ increments i, and returns its old value; ++i increments i,
and returns the new value. When the actual incrementation takes place
is only guaranteed to be after the preceding sequence point, and before
the next; in your code, this means before the call to printf.
Beyond that (and largely because of that), if you modify the value of an
object, you're not allowed to access it anywhere else without an
intervening sequence point, except as needed to determine the new value.
You violate this rule, so your code has undefined behavior.
It's undefined behavior. the compiler is allowed to calculate the parameters in any order. your compiler just calculate it from right to left, so the rightest parameter is 0, and the 2nd is 1.
edit: as Seth said, the compiler is only free to change the order of calculating, not to do whatever it wants, so when you don't care about the order you can freely call functions, but you should never assume that one parameter is been calculated before another.
I think your question is not about how increment work. The phenomenon you have observed is about the order of passing parameter to a function. As far as I can remember, this is not defined by c++ standard, so it's a UNDEFINED BEHAVIOR. Meaning different compiler could have different implementation.
E.g.
One compiler could pass parameter from left to right, then a different could pass parameters from right to left.
You can have a better read of Sequence point here:
http://en.wikipedia.org/wiki/Sequence_point
printf("%d , %d",++i,i);
is undefined behavior.
Your are violating C sequence points rule:
(C99, 6.5p2) "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored."
Once I read in some book that when a statement is like this:
printf("%d , %d",++a,a);
The execution starts from right to left but outputted as left to right. Therefore you see the out as 1 0 - 'a' is calculated first = 0 then '++a' = 1, but displayed as 1 0
This is strange but yeah that's how it works.
Hope this helps.
I recently got confused by the following c++ snippet:
#include <cstdio>
int lol(int *k){
*k +=5;
return *k;
}
int main(int argc, const char *argv[]){
int k = 0;
int w = k + lol(&k);
printf("%d\n", w);
return 0;
}
Take a look at line:
int w = k + lol(&k);
Until now I thought that this expression would be evaluated from left to right: take current value of k (which before calll to lol function is 0) and then add it to the result of lol function. But compiler proves me I'm wrong, the value of w is 10. Even if I switch places to make it
int w = lol(&k) + k;
the result would be still 10. What am I doing wrong?
Tomek
This is because the parameters in an expression are not specified to be evaluated in any particular order.
The compiler is free to execute either parameter k or lol(&k) first. There are no sequence points in that expression. This means that the side-effects of the parameters can be executed in any order.
So in short, it's not specified whether the code prints 5 or 10. Both are valid outputs.
The exception to this is short-circuiting in boolean expressions because && and || are sequence points. (see comments)
This code either yields 5 or 10 depending on the choice of evaluation oder of the function call relative to that of the left side of +.
Its behavior is not undefined because a function call is surrounded by two sequence points.
Plus is by definition commutative, so the order in your example is totally implementation-defined.
Mysticial is right when mentioning sequence points. Citing Wikipedia article (don't have C++ standard at hand):
A sequence point in imperative programming defines any point in a
computer program's execution at which it is guaranteed that all side
effects of previous evaluations will have been performed, and no side
effects from subsequent evaluations have yet been performed. They are
often mentioned in reference to C and C++, because the result of some
expressions can depend on the order of evaluation of their
subexpressions. Adding one or more sequence points is one method of
ensuring a consistent result, because this restricts the possible
orders of evaluation.
The article also has a list of sequence point in C++.