Unexpected working of printf() in C [duplicate] - c

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 9 years ago.
#include<stdio.h>
int main()
{
int i=2;
printf("%d %d \n",++i,++i);
}
The above code gives an output 4 4. Can any one help how to explain the output?

++i is a prefix increment. Printf should first evaluate its arguments before printing them (although in which order, is not guaranteed and, strictly speaking, undefined - See Wiki entry on Undefined Behavior: http://en.wikipedia.org/wiki/Undefined_behavior ).
The prefix increment is called "increment and fetch", i.e. it first increments the value and then gives it to the caller.
In your case, i was first incremented twice, and only afterwards the output was formatted and sent to the console.

It has to do with sequence points and it can result in undefined behavior.
Straight from Wikipedia:
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.
More info here: http://en.wikipedia.org/wiki/Sequence_point

Both the answers have made the same mistake. Its clear cut UB and not just unspecified behavior.
What you have experienced is Undefined behavior. Please read about sequence points. Comma is a separator in function calls not an operator.
A sequence point is a point in time at which the dust has settled and all side effects which have been seen so far are guaranteed to be complete. The sequence points listed in the C standard are:
at the end of the evaluation of a full expression (a full
expression is an expression statement, or any other expression which
is not a subexpression within any larger expression);
at the ||, &&, ?:, and comma operators; and
at a function call (after the evaluation of all the arguments, and just before the actual call).
The Standard states that
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 accessed only to determine the
value to be stored.
What will be evaluated first this "%d %d \n", this ++i or this ++i (second one) - think about it. This would be unspecified behavior:
void f(int x)
{
printf("%d ",x);
}
int main()
{
int i=0;
f(i++) ;
}
From wiki:
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. Similarly, j and k are updated before
entering g and h respectively. However, it is not specified in which
order f(), g(), h() are executed, nor in which order i, j, k are
incremented. Variables j and k in the body of f may or may not have
been already incremented. Note that a function call f(a,b,c) is not a
use of the comma operator and the order of evaluation for a, b, and c
is unspecified.

Related

printf() function evaluation of pre and post decrements in C [duplicate]

This question already has answers here:
Parameter evaluation order before a function calling in C
(7 answers)
Undefined behavior and sequence points
(5 answers)
Closed 8 years ago.
#include<stdio.h>
int main()
{
int i = 2;
printf("\n %d %d %d \n",--i,i--,i); // 0 2 2
return 0;
}
The output prints 0 2 0 and not 0 2 2.I couldn't understand, as I assumed that the printf() evaluates from right to left.
Your code exhibits Unspecified behaviour. As per c99 standard document, chapter 6.5.2.2, paragraph 10:
The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.
Again, this shows undefined behaviour, because, i is getting modified more than once between two sequence points. As per chapter 6.5 paragraph 2:
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.
printf evaluates nothing. It is the compiler that evaluates arguments of a function (that is it is the compiler that generates the object code) and the order in which the arguments will be evaluated in C is unspecified. So the compiler may evaluates them in any order.

unable to understand how expressions are getting false [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Parameter evaluation order before a function calling in C
(7 answers)
Closed 8 years ago.
int main( )
{
int k = 35 ;
printf ( "\n%d %d %d", k == 35, k = 50, k > 40 ) ;
}
The output of the above program is "0 50 0" without quotes. My question is how k==35 and k > 40 are false? From my perspective, k is assigned 35 so "k==35" should be true; then k is assigned 50 in "k=50", so "k > 40" has to be true, doesn't it?
The printf call invokes undefined behaviour.
The order of evaluation of arguments to a function is unspecified behaviour. It means that the arguments can be evaluated in any order from a set of all possible orders. The standard does not require the implementation to enforce any order. Also, the comma which separates the arguments is not the comma operator. This means there is no sequence point between the evaluation of the arguments. The only requirement is that all the arguments must be fully evaluated and all side effects must have taken place before the function is called. Now, the C99 standard §6.5 ¶2 says
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.
The evaluation of the arguments to a function is unsequenced. The assignment expression k = 50 evaluates to 50 but its side effect is to assign 50 to k. If this expression is evaluated first and its side effect immediately takes place, then the expression k == 35 would evaluate to true and k > 40 would evaluate to false. Thus depending on when the side effect of expression the k = 50 takes place, the other two expressions would evaluate to true or false. However, the other two expressions violate the second point in the above quoted part from the standard. The expressions access k but it is not to change the value of k. This violates the prior value shall be read only to determine the value
to be stored clause. This is the reason for the undefined behaviour.
Just to emphasize, the undefined behaviour in your code is not because the order of evaluation of arguments is unspecified (not undefined, which is different), but it's because there's no sequence point between the evaluation of the arguments, and as a result, the above quoted part from the standard is violated in this context.
Undefined behaviour means the behaviour of the code is unpredictable. Anything can happen from program crash to your hard drive getting formatted to demons flying out your nose (to launch into hyperbole). This is only to emphasize that the standard does not require the implementation to deal with such cases and you should always avoid such code.
Furhter reading -
What Every C Programmer Should Know About Undefined Behavior
Undefined Behavior and Sequence Points
Why is f(i = -1, i = -1) undefined behavior?
Order of evaluation
Your code invokes undefined behaviour because of the assignment in the argument list:
k = 50
You presumably want:
printf("%d %d %d\n", k == 35, k == 50, k > 40);
Since you embed an assignment in the argument list, any result is permissible. There is no required order of evaluation for arguments; they could be evaluated in any order — any result is correct. For your own sanity, do not ever write code that depends on the order of evaluation of arguments.
If the book you are learning from is not simply emphasizing that the order of evaluation is undefined and that any undefined behaviour is bad, then you should probably discard the book.
It is Undefined Behavior, which means anything may happen.
Why is it UB?
The answer is simply that there is no ordering constraint, not even indeterminate sequencing, between a write of k and a read of k which is not used to determine the new value of k.
printf ( "\n%d %d %d", k == 35, k = 50, k > 40 );
// No ordering constraint between function arguments.
Aside: If the write happened in a function called in the argument list instead (not in the arguments to that function), it would be indeterminately sequenced and thus not UB.
Indeterminately sequenced means it is sequenced before or after without determining which. It is not quite as bad as UB (anything goes), but it should still not be relied on, as the order is unreliable.
int SetVar(int *p, int v) {return *p = v;}
printf ( "\n%d %d %d", k == 35, SetVar(&k, 50), k > 40 );
// No ordering constraint between function arguments, but
// the function call is indeterminately ordered

Is `a++ & f(a)` undefined or unspecified?

This is an example from Deep C (slide 194)
int a = 41;
a++ & printf("%d\n", a);
The presentation claims that the result is undefined. Why? a is only assigned once between the sequence points. I think that the execution order between a++ and printf would be unspecified, so that this would print either 41 or 42 on all conforming compilers, with no undefined behavior.
In this line - a++ & printf("%d\n", a); there is only one sequence point (not counting what happens in function arguments - since a++1 happens in this line itself) - modifying a variable and reading from it at the same time within a single seqeunce point is UB. Behavior is undefined if a previous value is read from the object but there is a modification too, as in i * i++
&& is a sequence point, & is not a sequence point if that is where you were confused.
A sequence point is a point in time at which the dust has settled and all side effects which have been seen so far are guaranteed to be complete. The sequence points listed in the C standard are:
at the end of the evaluation of a full expression (a full
expression is an expression statement, or any other expression which
is not a subexpression within any larger expression);
at the ||, &&, ?:, and comma operators; and
at a function call (after the evaluation of all the arguments, and just before the actual call).
The Standard states that
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 accessed only to determine the
value to be stored.
The bitwise operator & doesn't introduce a sequence point, so that is indeed undefined behavior.

post increment and pointer in printf [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 9 years ago.
Can someone please explain why this code is outputing 2 1, I thought post-increment was supposed to be applied after the printf instruction.
#include <stdio.h>
int main() {
int i=1;
int *p=&i;
printf("%d %d\n", *p ,i++);
return 0;
}
The order of evaluation of is not specified for this case in the standard and so you can not determine whether *p or i++ will be evaluated first. The C99 draft standard says in section 6.5.2.2 Function calls paragraph 10 says:
The order of evaluation of the function designator, the actual arguments, and
subexpressions within the actual arguments is unspecified, but there is a sequence point
before the actual call.
This is also undefined behavior because you are modifying i and accessing the previous value of i in another expression within the same sequence point, the draft standard in section 6.5 Expressions paragraph 2 says:
Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression.72) Furthermore, the prior value
shall be read only to determine the value to be stored
Comma is a sequence point, but not in function calls.
And printf is a function with arguments separated with commas.
In expression like this:
if(i+2,i++). . . comma is a sequence point and assures that expressions will be evaluated from left to right, and final value of expression will be value of rightmost sub-expression. In this case i++.
On the other hand in funcion call:
function(i+1,i++,i--) comma in not a sequence point and any of sub-expressions can be evaluated as first. The only thing sure is that they all be evaluated, but not in any specific order.

array manipulation results

can someone provide me more insight on why this code works the way it works
#include <stdio.h>
int main()
{
int a[5] = {1,2,3,4,5};
int i;
for(i=0;i<5;i++)
{
printf("%d,%d \n",i[a],i[a]++);
}
return 0;
}
The result is
2,1
3,2
4,3
5,4
6,5
Thanks
The behavior is undefined.
N1256 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.
The program both modifies i[a] (in i[a]++) and reads its value (in the next argument), and the result of reading the value is not used to determine the value to be stored.
This is not just a matter of the unspecified order of evaluation of function arguments; the fact that there's no sequence point between i[a]++ and i[a] (since that's not a comma operator) means that the behavior, not just the result, is undefined.
It works by undefined behaviour. The order of evaluation of function arguments is not defined. The comma is not a sequence point.
EDIT: ooops, I read to fast. There is only one write to the a[i] object, so the behaviour is not undefined, only the results.
"i[a]++" is a post increment, so it will return the value of i[a] and then increment i[a] right away.
In your case, the third parameter of printf gets evaluated before the second (the evaluation order of function parameters is unspecified as far as I know), and thus the second parameter returns the already incremented value.

Resources