This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 4 years ago.
#include<stdio.h>
main()
{
int a=10;
printf("\n %d %d", a, a++); //11 10
a=10;
printf("\n %d %d", a++, a); //10 11
a=10;
printf("\n %d %d %d ", a, a++,++a); //12 11 12
}
after running this I got the output given in comments. as far as I know first output is expected because execution of printf goes from right to left but could not understand second and third
Nothing goes "from right to left" in function argument evaluation. When function arguments are evaluated, the order of evaluation is unspecified and there are no sequence points between evaluating separate arguments. This means that there's absolutely no temporal ordering in this process. The arguments can be evaluated in any order, and the process of their evaluation can be intertwined in any way.
However, your code suffers from even worse problems. All three statements that call printf produce undefined behavior (UB) because they either make an attempt to modify the same object (a) twice without a sequence point between the modifications (the third call), or they attempt to modify an object and read it for an independent purpose (the first and the second call). So, it is too early to even mention the order of evaluation. Your code's behavior is undefined.
None of the outputs can really qualify as unexpected. All the arguments to a function are evaluated before entry to the function itself -- but the order of their evaluation relative to each other is unspecified, so all of these results are allowed. Officially, your last one (that has two separate instances of incrementing a) has undefined behavior, so it doesn't have to do anything sensible at all.
++a means increment a first, and then return evaluate the expression. (a changes, and the expression evaluates as a + 1)
a++ means evaluate a (so, erm, a), and then increment it. So a is passed, but the value of a is then (ie afterwards) changed to a+1.
You are invoking undefined behaviour by referencing both 'a' and 'a++' in the argument list.
It is not defined which order the arguments are evaluated in. Different compilers may choose different orders. A single compiler can choose different orders at different times.
Do not do it!
Function parameters are not evaluated in a defined order in C. Therefore one cannot tell beforehand if a or a++ will be evaluated first when calling printf.
See Parameter evaluation order before a function calling in C
Related
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 6 years ago.
I'm new in this community, and I'm trying to understand why this recursive function not get a stack overflow,when I use the post increment (c++) in the call of the function, this passes a value of 0 (i see that when i debug), but when the next function is called, it have a value of 1.
I dont understand when the post increment is applied, and why if im passing to the function the value of 0 , in the first argument is doing s+1;
#include <stdio.h>
#include <string.h>
#define LARGO 20
char *esta (char s[], int c){
if(strlen(s))
printf("\n %s", esta(s+c,c++));
return s;
}
int main()
{
char cad[LARGO]= {"hello"};
int c=0;
printf("\n %s", esta(cad,c++));
}
P.S. : Sorry if my english is not the best, It isn't my main language and i try to explain as well i could; and if it is something is not clear tell me and i change it.
The order in which arguments are evaluated is undefined, so the compiler can choose any order it wants to. It seems in your case, it's first evaluating c++ to 0, and then s+c evaluates to s+1.
See wikipedia Sequence point. In particular item #4 gives full explanation:
A sequence point 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.
Before a function is entered in a function call. The order in which the arguments are evaluated is not specified, but this sequence point means that all of their side effects are complete before the function is entered.
In the expression f(i++) + g(j++) + h(k++), f is called with a parameter of the original value of i, but i is incremented before entering the body of f.
In other words: compiler is assigned to do a tough job here. It must pass the original value which was there before POST-increment (because it is how POST-increment works) and at the same time perform all side effects BEFORE entering the function esta. Among these side effects is increment the value of c. And, since the order in which the arguments are evaluated is not specified it happens so that your compiler evaluates c++ first, and then does s+c which in this case means s+1. Hence your line is shorter and shorter and eventually strlen(s)==0 when you exit from the recursion and print string remainders at each iteration.
Code :
#include<stdio.h>
#include<stdlib.h>
int arr[] = {1, 2, 3, 4};
static int count = 0;
int incr( ) {
++count;
++count;
return count;
}
int main(void)
{
printf("\ncount= %d \n",count);
int i;
arr[count++]=incr( );
for(i=0;i<4;i++)
printf("arr[%d]=%d\n", i,arr[i]);
printf("\nIncremented count= %d \n",count);
return 0;
}
Output
count = 0
arr[0]=2
arr[1]=2
arr[2]=3
arr[3]=4
Incremented count = 1
The final incremented value of global variable count is 1 even though it has been incremented thrice.
When count++ is replaced by count in arr[count++]=incr( ) the final incremented value of count is 2.
This is undefined behaviour from bad sequencing. On this line:
arr[count++]=incr( );
What happens (with your compiler) is:
arr[count] is resolved to arr[0], postfix ++ will be applied at the end of the
statement;
incr() is called, count is now equal to 2, incr() returns 2;
arr[0] gets assigned 2;
postfix ++'s side effect kicks in, and count is now equal to 1. Previous changes to count are lost.
You will find more info on "side effects" and "sequence points" by googling their real name :)
To understand why your code goes wrong, you must first understand undefined behavior and sequence points, which is a rather advanced topic. You also need to understand what undefined behavior is, and what unspecified behavior is, explained here.
If you do something to a variable which counts as a side-effect, such as modifying it, then you are not allowed to access that variable again before the next sequence point, for other purposes than to calculate which value to store in your variable.
For example i = i++ is undefined behavior because there are two side effects on the same variable with no sequence point in between. But i = i+1; is well-defined, because there is only one side effect (the assignment) and the i+1 is only a read access to determine what value to store.
In your case, there is no sequence point between the arr[count++] sub-expression and the incr() sub-expression, so you get undefined behavior.
This is how sequence points appear in functions, C11 6.5.2.2:
There is a sequence point after the evaluations of the function
designator and the actual arguments but before the actual call. Every
evaluation in the calling function (including other function calls)
that is not otherwise specifically sequenced before or after the
execution of the body of the called function is indeterminately
sequenced with respect to the execution of the called function.
This means that the contents of the function aren't sequenced in relation to the rest of the expression. So you are essentially writing an expression identical to arr[count++] = ++count;, except through the function you managed to squeeze in two unsequenced ++count on the right side of the operation, which wouldn't otherwise be possible. Any any rate, it is undefined behavior.
Fix your code by enforcing sequence points between the left hand and the right hand of the expression. However, the order of evaluation of sub-expressions is unspecified behavior, so you need to ensure that your code is safe no matter if the left or right side is evaluated first. This code will fix the problems:
// artificial example, don't write code like this
0,arr[count++] = 0,incr();
since the comma operator introduces a sequence point. But of course, writing nonsense code like that isn't something you should be doing. The real solution is to never use ++ together with other operators in the same expression.
// good code, write code like this
arr[count] = incr();
count++;
Program 1:
#include<stdio.h>
void main()
{
int i=55;
printf("%d %d %d %d\n",i==55,i=40,i==40,i>=10);
}
Program 2:
#include<stdio.h>
void main(){
int i = 55;
if(i == 55) {
printf("hi");
}
}
First program give output 0 40 0 1 here in the printf i == 55 and output is 0 and in the second program too i ==55 and output is hi. why
In the first example, the operators are evaluated in reverse order because they are pushed like this on the stack. The evaluation order is implementation specific and not defined by the C standard. So the squence is like this:
i=55 initial assignment
i>=10 == true 1
i==40 == false (It's 55) 0
i=40 assignment 40
i==55 == false (It's 40) 0
The second example should be obvious.
There's no guarantee about the order in which arguments to a function are evaluated. There's also no sequence point between evaluating the different arguments to the function.
That means your first call gives undefined behavior, because it both uses the existing value of i and writes a new value to i without a sequence point between the two.
In a typical case, however, each argument to a function will be evaluated as a separate expression, with no interleaving between them. In other words, the compiler will impose some order to the evaluation, even though the standard doesn't require it to do so.
In the specific case of a variadic function, the arguments are typically pushed onto the stack from right to left, so the first argument (the format string) will be at the top of the stack. This makes it easy for printf to find the format string, and then (based on that) retrieve the rest of the arguments from further down the stack.
If (as is fairly typical) the arguments are evaluated immediately prior to being pushed on the stack, this will lead to the arguments being evaluated from right to left as well.
Functions with a fixed number of arguments aren't evaluated from right to left nearly as often, so if (for example) you wrote a small wrapper taking a fixed number of arguments, that then passed those through to printf, there's a greater chance that i would have the value 55 when the first argument to printf is evaluated, so that would produce a 1 instead of a 0.
Note, however, that neither result is guaranteed, nor is any meaningful result guaranteed--since you have undefined behavior, anything is allowed to happen.
The arguments of printf are evaluated from right to left here (this is unspecified behavior, but the behaviour you noticed shows that at least the first argument is evaluated after the second). In your argument list there ist i=40, which sets the value to 40. Therefore the first printed argument is false (0).
The function printf evaluates the expressions in implementation specific manner, in this case from right to left. Hence the output:
i==55(0),i=40(Assignment),i==40(0),i>=10(1)
The reason is that the order in which the arguments to the printf function (actually any function) are evaluated, before being passed to the function, is not defined by the C standard.
The problem is not with your understanding of the == operator.
Edit: Although many authors are pointing out that printf typically evaluates its arguments from right-to-left (which I wasn't aware of), I would say it's probably a bad idea to write code that depends on this, as the language does not guarantee it, and it makes the code much less readable. Nevertheless is is a good factoid to know in case you come across it in the wild.
In the first program: The order of evaluation of the printf() arguments is implimentation defined. So this program doesn't give the same result on different implimentation of printf() So there is no guarantee about what the program will result.
It could output 0 40 0 1 as it could output 1 40 1 1 if the order of evaluation is reversed.
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 5 years ago.
Here is my simple code ...
#include<stdio.h>
int main()
{
int i=5;
printf("%d %d %d %d %d ",i++,i--,++i,--i,i);
return 0;
}
On gcc,it gives output as '4 5 5 5 5'
but on TC,it gives output as '4 5 5 4 5'
what I know that in printf statement,evaluation will be from left to right if it is a single expression but in normal statement,it will be from left to right.
but if printf contain multiple expressions,then evaluation will be on stack,the elements would be pushed onto stack from left to right but popped out from right to left and that justified the TC output
Please correct me where am I wrong ???
C does not specify which order function arguments should be evaluated in, and so it is undefined and a compiler can do it however they choose, including arbitrarily and randomly. Bjarne Stroustrup says this explicitly in "The C++ Programming Language" 3rd edition section 6.2.2
He also gives a reason:
Better code can be generated in the absence of restrictions on expression evaluation order
I think the order in which the arguments of a function call are evaluated is not specified. As wikipedia says in this article on sequence points:
The order in which the arguments are evaluated is not specified
Modifying an object (in this code i) more than one time between the previous and the next sequence point is undefined behavior in C. Here the sequence point occurs at the function call after all arguments have been evaluated.
The two answers at this point in time invoke the unspecifiedness of the evaluation of function arguments. The correct answer is that your program is undefined because of side-effects to the same variable not separated by a sequence point.
Indeed, the evaluation order of function arguments is unspecified. This means that in the statement f(g(), h());, either g() is called before h() or it is called after.
However, unsequenced side-effects (as in your program) invoke undefined behavior, where anything can happen.
Bumping up an old topic but I just found how the gcc and Visual Studio Compiler works on multiple changes on the same variable in a statement so thought of sharing it here.
The compiler as defined here starts to implement stack method on the arguments being passed in printf which is 'i'. It follows these rules:-
1) Now it executes the pre-increments first therefore starting from right normal i then --i and then ++i are executed and the value of i after ++i is 5 so it implements these values (pops) so output is _ _ 5 5 5
2) Then it continues right to left and executes post increments therefore, i-- and then i++ so the value of i in the end is back to 5 but due to i-- it becomes 4 but shows 5 due to it being a post increment therefore the final output is 4 5 5 5 5 and the final value of i is 5
Hope I am able to clear your doubts.
TC doesn't follow this so it adheres to our human logic.
I have a function that multiply two matrices A and B then prints the result.
I got two different outputs when running the program in two similar ways.
first:
FILE *f;
f = fopen("in.txt","r");
struct Mat* A = read_mat(f);
struct Mat* B = read_mat(f);
print_mat(mat_mul_1(A, B));
the output was the exact multiplication of
A * B
second:
FILE *f;
f = fopen("in.txt","r");
print_mat(mat_mul_1(read_mat(f), read_mat(f)));
the output was the exact multiplication of
B * A
I want to know why the arguments has been reversed ?!
(as the 'mat_mul_1' function is a black box)
Did you expect that the first read_mat(f) would be evaluated first?
C offers no such guarantees. The compiler is free to emit code that evaluates the arguments in any order it chooses.
The order of evaluation of the function designator, the actual arguments, and
subexpressions within the actual arguments is unspeciļ¬ed, but there is a sequence point
before the actual call.
The reason why is as others have already pointed out, the order of evaluation of function parameters is unspecified behavior, and therefore should not be relied upon. But there is another, possibly severe issue here:
The function read_mat could be accessing static resources, such as static/global variables, and then return their values. Like this:
static int x;
int inc (void)
{
x++;
return x;
}
printf("%d %d", inc(), inc());
The actual result of the function will vary depending on the order of evaluation.
(This snippet is taken from an interview test I use when hiring C programmers. I ask what the output of this code is, and the correct answer is "2 1" or "1 2". The question tests whether the C programmer knows of the concepts static initialization and order of evaluation.)
It's because of the order parameters to the function are evaluated:
print_mat(mat_mul_1(A, B));
will call mat_mul_1(A, B), where A is the first matrix in the file and B is the second.
In your second case:
print_mat(mat_mul_1(read_mat(f), read_mat(f)));
I'm guessing(since it's not specified by the standard) that, on your system, is calling the second read_mat() first, and will thus call mat_mul_1(B, A);
The reason being is that the right-most read_mat(f) is called before the left-most one, and you're therefore reading the first structure into what you would presume to be B. Therefore A and B are reversed.
I kind of make sense of it in that arguments are pushed on the stack in reverse when they're passed to a function, therefore they're evaluated from right to left.
I'm not sure there's any standard defining what must be evaluated first.
Your code has undefined behaviour because the FILE pointed to by f is modified by both the first and the second read_mat(f) and no sequence point exists between these two modifications.