This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 7 years ago.
While solving some aptitude questions on C programming language and I encountered a problem in which I have to tell the output. The program is :-
#include<stdio.h>
int main()
{
int x = 5;
printf("%d %d %d", ++x, x++, ++x);
return 0;
}
Now from my previous knowledge I know that the parameters of a printf() function are evaluated right to left. So solving this manually I'm getting output as :- 8 6 6
But the when I compiled this program I got the output as :- 8 6 8
Okay here is the question that seems bit related to this question but, there I'm specifically asking for the execution of parameters in the function not for the assignment operators.
Or does the execution of parameters happens randomly? If so, then some time it should give some different output but it is not giving. Even on different compilers it is giving the same output as 8 6 8.
why this anomaly?
Thanks
The order of evaluation in printf() is not left to right as you assumed. The evaluation order is unspecified:
From C11 draft (Annex J, unspecified behaviours)
The order in which the function designator, arguments, and
subexpressions within the arguments are evaluated in a function call
(6.5.2.2).
From, 3.4.4, unspecified behavior
Use of an unspecified value, or other behavior where this
International Standard provides two or more possibilities and imposes
no further requirements on which is chosen in any instance.
EXAMPLE An example of unspecified behavior is the order in which the
arguments to a function are evaluated.
So the three x++ expressions can be evaluated in any order. But this leads to undefined behaviour as you are attempting to modify the same object more than once without an intervening sequence point. The comma in a function designator is a separator, not the comma operator.
Because comma operator does introduce a sequence point between its operands.
The behavior is definitely unexpected, You are not supposed to change the value of a variable more than once in a function call. Rules of sequence points. Try looking at this link. And also read about sequence points in a program
Just try not changing the value of one variable more than once in a function call
There are two things interfering here:
the order of evaluation of function arguments is undefined (causing undefined results) -> the order can be anything because there is no order imposed by The Standard (The standard says: the order is unspecified)
there are no sequence points between the evaluations of the function arguments. (the function calling per se, and its return are sequence points, but that's irrelevant here)
What this means in practice: because the evaluating of the function arguments has side effects (the increments) there are multiple attempts to alter x's value without an intervening sequence point, causing Undefined Behaviour.
Related
I would like to understand this code snippet as much as the undefined behavior permits it:
int i = 0;
printf("%d %d %d", i, ++i, i++);
output:
2 2 0
From what I can tell:
a comma , defines a sequence
the actual printing happens when all of the sequences are evaluated inside the function argument call
since arguments are pass-by-value, a copy happens sometime(?!) while calling the function
the order in which the function argument sequences evaluated is undefined ( is this true? )
So as far as I can tell most of the behavior in that single line of code is undefined, still I would like to understand the parts that are NOT undefined behavior.
I know the output depends on the compiler, but what parts are there that are defined in the C Standard?
I am interested in ANSI C, C99 as well, but I believe latest C++ standards improved on this at least in some aspects, is that true?
a comma , defines a sequence
No. Don't confuse the comma operator (What does the comma operator , do?) for a function argument list. The actual , symbol is used in a lot of different places in the C syntax, but the only place where it has a well-defined order of evaluation is when it's used for the actual comma operator. Neither function call argument lists nor initializer lists have well-defined orders.
The C standard says this about function calls and arguments (C17 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.
I your case the 4 arguments "%d %d %d", i, ++i, i++ are indeterminately sequenced in relation to each other and the sequence point, as mentioned above, is placed after the evaluation of the arguments.
To address your other statements:
the actual printing happens when all of the sequences are evaluated inside the function argument call
Correct, but then undefined behavior has already struck.
since arguments are pass-by-value, a copy happens sometime(?!) while calling the function
You can assume that these are pass by value indeed. printf is an icky variadic function so they end up in a va_list, which I believe has an implementation-defined representation internally.
the order in which the function argument sequences evaluated is undefined ( is this true? )
The order of evaluation of function arguments is unspecified behavior, meaning we can't know the order - it can be undocumented - and therefore we shouldn't assume a particular order. The actual undefined behavior happens because of 6.5/2:
If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.
I would like to understand the parts that are NOT undefined behavior.
I'm not sure what you mean with that, since code can't be "just a little bit undefined". If it has undefined behavior and then all bets are off regarding anything in that program. You can't reason about it or it wouldn't be undefined, but something else. Therefore it doesn't make sense to reason like "undefined behavior turns this value to 55 and then it is passed by value". For example maybe the UB causes the whole function call to be optimized away or get inlined in strange ways.
Why does the following code produces this output:
Code Snippet:
int a=10;
printf("%d%d%d",++a,a++,++a);
Output:
131113
How are are parameters evaluated? Does this depend upon compiler? I use gcc compiler. Can anybody tell me how my compiler evaluated it? If the compiler evaluates parameters of a function from Right to Left then will the output of this code be the following:
121111
That is Undefined Behavior. Modifying a variable more than once in a sequence point is Undefined Behavior.
From Wiki:
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.
Please read: Operator Precedence vs Order of Evaluation
For a thorough understanding please read: Undefined Behavior and Sequence Points
You can do this though:
int a=10;
int b = (++a,a++,++a);
Because the Comma (,) is an operator here and not just a mere separator between the arguments as in case of printf.
This is actually a combination of both unspecified behavior and undefined behavior.
It is unspecified because the order of evaluation of function arguments is not specified so in this line:
printf("%d%d%d",++a,a++,++a);
^ ^ ^ ^
1 2 3 4
we do not know which order functions arguments 1 to 4 will be evaluated and it is even possible that if this was in a loop that on subsequent executions the order could be different. This is covered in the C99 draft standard section 6.5.2.2 Function calls paragraph 10 which says(emphasis mine):
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.
By itself this means the output of the program is unreliable but we also have undefined behavior due to the fact that the code above modifies a multiple times within one sequence point. This is covered by section 6.5 Expressions paragraph 2 which says(emphasis mine):
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.73)
Undefined behavior means that anything could result from running this program including that it appears to work correctly, the term is defined in section 3.4.3 and includes the following note which explains the possible result of undefined behavior:
Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
Beyond that even if you could obtain reliable results code like that is hard to read and would be a nightmare to maintain in a complex project. If there are alternative simpler ways to write the code that meets other requirements such as performance etc... then that is the approach you should take.
This question already has answers here:
Is C/C++ bool type always guaranteed to be 0 or 1 when typecast'ed to int?
(6 answers)
Closed 9 years ago.
Why does the below program gives me the opposite answer after comparison operations are done?
main()
{
int k=35;
printf("%d\n%d\n%d",k==35,k=50,k<40);
}
output
0
50
1
This program is not a valid C program as per the C standard.
There are 2 problems associated with this program.
Problem 1: Unspecified Behavior
The order of evaluation of arguments to a function is Unspecified[Ref 1].
It could be left to right or
It could be right to left or
Any other magical order
Problem 2: Undefined Behavior
This has undefined behavior[Ref 2] because a variable should not be modified more than once without a intervening sequence point. Note that , in the function arguments does not introduce a sequence point. Thus k gets modified without a intervening sequence point and causes Undefined Behavior.
So you cannot rely on the behavior to be anything specific in this case. The program is not a valid C program.
[Ref 1]
C99 Standard 6.5.2.2.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.
[Ref 2]
C99 Standard 6.5.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 accessed only to determine the value to be stored.
Note that Unspecified and Undefined Behavior are terms defined by the standard as:
C99 Standard 3.19 Unspecified Behavior:
behavior where this International Standard provides two or more possibilities and
imposes no requirements on which is chosen in any instance
C99 Standard 3.18 Undefined Behavior:
behavior, upon use of a nonportable or erroneous program construct, of erroneous data, or
of indeterminately valued objects, for which this International Standard imposes no
requirements
Did you notice that the second argument to printf is k=50? This is an undefined behavior because the order of evaluation of the parameters is unspecified
The order of evaluation of function arguments is not defined by the C standard. See C99 §6.5.2.2p10:
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 means that each of the comparison k==35, the assignment k=50, and the test k<40 can happen in any order. When I tried your program using MSVC, the assignment happened first. Other compilers, or even other invocations of the same compiler, may choose different orders.
I wish you'd shown your output. However, my suspicion is that the problem is that you've included an assignment as one of the arguments to printf(), and heavens knows what order the three arguments were evaluated, i.e. k might have been 50 when the k==35 was evaluated ;-)
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 5 years ago.
I printed the above line. But I got the result as 65.How does I increment and print despite the fact that I is incremented at the second time??
int i=5;
printf("%d%d",i,i++);
Your printf call produces undefined behavior. It is illegal to modify i (in i++) and at the same time perform an independent read of i without an intervening sequence point.
Various "orders of evaluation" do not matter here. All attempts to explain the behavior of this code based on the "orders of evaluation" or what happens "before" and what happens "after" are absolutely incorrect. The behavior is simply undefined. End of story.
As far as the C language itself is concerned, this code can print "Kill all humans!", crash the program, format your hard drive or simply refuse to compile.
The ANSI C99 ISO/IEC 9899:1999 standard says
6.5.2.2 Function calls
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.
as you just discovered, the order of evaluation is unspecified. The compiler is free to evaluate the arguments in any order. (In your case, i++ is evaluated before i.)
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 4 years ago.
main()
{
int i=5;
printf("%d%d%d%d%d%d",i++,i--,++i,--i,i);
}
Output is 45545, but I don't how it is working. Some say that the arguments in a function call are pushed into the stack from left to right.
The evaluation order of function parameters is unspecified.
From c99 standard:
6.5.2.2 Function calls
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.
This is, however, only a part of the problem. Another thing (which is actually worse, since it involves undefined behavior) is:
6.5 Expressions
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.
In our case all the arguments evaluation is between only 2 sequence points: the previous ; and the point before the function is entered but after all the arguments have been evaluated. You'd better not write a code like this.
C standard is pretty relaxed in some places to leave room for optimizations that compilers might do.
The order in which the parameters to a function are passed is not defined in the standard, and is determined by the calling convention used by the compiler.
I think in your case, cdecl calling convention (which many C compilers use for x86 architecture) is used in which arguments in a function get evaluated from right to left.
This function call is undefined behavior:
printf("%d%d%d%d%d%d",i++,i--,++i,--i,i);
Modifying an object more than once between two sequence points is undefined behavior in C.
It is also undefined behavior because you have 6 conversion specifications but only 5 arguments for the format.
Two points:
Function arguments are evaluated in an unspecified order. This allows the compiler to optimize however it likes.
Your particular arguments invoke undefined behavior. You're not allowed to modify i multiple times before a sequence point.
The evaluation order of printf arguments is unspecified. It depends, among other, on the calling convention of the system you are using. Moreover, this is also an undefined behavior, because you are modifying i several times without any sequence point. BTW, there is a missing argument.