void main()
{
int var1 = 10;
cout<<var1<<" "<<var1++<<" "<<++var1<<" "<<var1++;
}
And why? Thanks for your inputs.
Printable View
void main()
{
int var1 = 10;
cout<<var1<<" "<<var1++<<" "<<++var1<<" "<<var1++;
}
And why? Thanks for your inputs.
Undefined due to the errors.
Maybe I should expand on that:Quote:
Originally Posted by dullboy
- it's int main(), not void main()
- you cannot modify the stored value of a variable more than once between sequence points. This is what the "cout" line is doing. The behaviour is undefined, therefore the output of the program cannot be predicted.
The output is:
'cout' : undeclared identifier
because you forgot to include <iostream.h>
Seriously, though, it should be:
13, 12, 12, 10
Starting at the right, the variable value is printed, then incremented. So, "10" goes to cout (eventually). Then it is incremented to 11.
The increment that occurs to the left of this happens before the value is sent to cout, so it is incremented to 12, then printed.
Similarly with the last (err, first) two.
Thanks for your reply. But if you run this program, output would be "13 12 12 10". I don't understand the output.
Quote:
Originally Posted by Graham
Scratch the .h and we agree.Quote:
Originally Posted by Bond
There is no guarantee that the right expression will be evaluated first, so the results are, as Graham correctly pointed out, undefined.Quote:
Originally Posted by Bond
But my question is that why it is starting at the right instead of left? For example, int x = 1; int y = 2; cout<<x<<y; Then the output is 1 2 instead of 2 1.
Quote:
Originally Posted by Bond
Don't try to understand the output. If you ran this on another compiler, in all likelihood the output is different. That is what is meant by "undefined behavior".Quote:
Originally Posted by dullboy
Regards,
Paul McKenzie
Even you are right, there is always logics behind the output, which I try to understand.
Quote:
Originally Posted by Paul McKenzie
Why not concentrate on learning how not to write code like this, and concentrate on proper C++ coding techniques?Quote:
Originally Posted by dullboy
There is no "logic" behind the output. Once you introduce undefined behavior, then anything under the hood could be happening. The answer can be 1,489,423,324 for all it's worth. Again, the behavior is undefined.
Regards,
Paul McKenzie
operator<< is a function, the order of evaluation for function arguments are undefined: http://www.research.att.com/~bs/bs_f...aluation-order
If you want to know why your compiler is evaluating function arguments from right to left or vice-versa, ask your compiler vendor.
Look, it's quite simple: you are not allowed to modify the stored value of a variable more than once between sequence points. This program attempts to modify it three times between sequence points. Order of evaluation of arguments is totally irrelevant - it's an illegal statement.
And just in case it needs hammering home, here's the relevant paragraph from the standard (Section 5, para 4):
Quote:
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 unspecified. 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.
Yes, operator<<() is a function, but something likeQuote:
Originally Posted by cma
is not one function call. First, the compiler looks atCode:cout << a << b;
cout << a, and calls the corresponding operator<<() function (which takes *one*argument, so there is no question about the order of evaluation of function arguments). The function then returns the ostream value that invoked it (in this case, cout) so now the expression looks like this:
This once again evaluates to the right operator<<() call.Code:cout << b;
And yes, the operator<<() call that processes "a" is called first, and the operator<<() call that processes "b" is called second and this is perfectly well defined and that's why "a" gets inserted into the output stream before "b" does.
The only reason
is undefined is because you are trying to modify the *same* variable three times. If it were 3 different variables, as such.Code:cout<<var1<<" "<<var1++<<" "<<++var1<<" "<<var1++;
then everything, including the output and the order in which the functions are called, is well defined.Code:int var1, var2, var3;
... // initialize them to something
cout<<var1<<" "<<var1++<<" "<<++var2<<" "<<var3++;
Note that
is OK because even though you're outputting the same variable twice, you're only actually modifying it once.Code:cout << var1 << " " << var1++;
Nitpick: it takes two arguments - don't forget the ostream&. Otherwise, you're quite right.Quote:
Originally Posted by HighCommander4
Actually, it depends. The ones overloaded to take basic types as arguments are member functions of ostream and as such take one argument. Any custom overloads will be non-member functions and thus take 2 arguments.Quote:
Originally Posted by Graham
<super-nickpicky> Actually, even the member functions take two arguments, because this is implicitly passed to member functions. </super-nickpicky>Quote:
Originally Posted by HighCommander4
All right, point taken. ;)Quote:
<super-nickpicky> Actually, even the member functions take two arguments, because this is implicitly passed to member functions. </super-nickpicky>
Output is: 10 10 12 12Quote:
Originally Posted by dullboy
Surely
cout << var1 << var++ << ++var1 << var1;
is the same as
cout.operator << (var1).operator << (var1++).operator << (++var1).operator << (var1);
which is the same as
cout.operator << (var1);
cout.operator << (var1++);
cout.operator << (++var1);
cout.operator << (var1);
I don't see any potential undefined results here?
Although the original line of code appears to be one statement, it is actually four seperate function calls in a defined order.
Or am I missing something?
Now
foo(var1, var1++, ++var1, var1);
would definitely be undefined.
It is not the same. The original statement has a single sequence point (at the semicolon), before which it modifies the stored value of var1 three times. This is not allowed, as has been pointed out previously. The four function calls are not in a "defined" order - at least, the evaluation of the arguments to those functions has no defined order, and that's where the problem lies.Quote:
Originally Posted by JohnW@Wessex
Recasting it into four statement introduces three new sequence points - var1 is never modified more than once between any two of these sequence points, the sequence points impose an ordering on the argument evaluation, and so the recast version is fine.
By splitting up into separate statements, you are forcing an evaluation order and allowing multiple updates to the value (one per sequence point), neither of which hold in the single-statement form.
The point about sequence points is that they are defined places where all expressions up to that point have been fully evaluated and all side-effects have completed. Between sequence points, there are no guarantees.
C++ standard, 1.9/7:
I've quoted chapter and verse about this from the standard further up the thread. For the umpteenth time, the "cout" statement in the original post invokes undefined behaviour.Quote:
[...] At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.
Yes, there can be multiple function calls executed in a single statement.
And the standard says that only one of these may modify a variable.
I don't know what the defined behaviour is when a variable appears in a statement multiple times and is modified exactly once (which could be a non-const function being called on it).
Note that while the behaviour is undefined, the code compiles.
And maybe the reason why I don't know the behaviour of the above is doing so would make the code look ambiguous. The only times we "know" the effect of is using post-increment ++ once inside a statement, whereby the object is modified but the old value is used.
Now, to be nitpicky, in this statement:
os is modified 3 times, because << is a non-const function (and so it should be). Yet the behaviour is well defiined.Code:os << a << b << c;
Is this undefined?
I think here i should always be 3.Code:int i=0;
cout << ++(++(++i));
In this statement though:
Now i++ will return 0 and the left hand ++ will modify that 0 to 1 but will it be modifying i or a temp? operator++(int) normally returns a copy of the object that was updated. Will it compile? What will be the value of i at the end of the statement?Code:int i=0;
cout << (++(i++))++;
If you go back to post #13, where I posted the quote from the standard, you'll see that it says [...]a scalar object[...]. Which opens the question of whether that paragraph also applies to scalar members of objects in expressions.Quote:
Originally Posted by NMTop40
Scalar means a basic type?
Pretty much, yes.Quote:
Originally Posted by HighCommander4
I get the point about,
"You are not allowed to modify the stored value of a variable more than once between sequence points"
Fine. Rules are made to follow.
But,
What is a sequence point? Is it the semi-colon?
Why is the sequence point so releavent?
Why is it that,
the behaviour is undefined if i try to do as in POST#1,
but defined if i try....
What i mean is what happens behind the scenes, with respect to the sequence points?Code:++obj;
obj = obj+7;
And yes, i did read this...
Quote:
The point about sequence points is that they are defined places where all expressions up to that point have been fully evaluated and all side-effects have completed. Between sequence points, there are no guarantees.
I followed the link and found about sequence points that:
Quote:
However, there's a sequence point after the evaluation of the arguments but before the call actually occurs.
Is a sequence of function calls, with only one (or zero) side effect at each function call.Code:cout<<var1<<" "<<var1++<<" "<<++var1<<" "<<var1++;
so, the result should be defined? And it should be 10 10 12 12
Am i wrong?
Just what I thought!Quote:
Originally Posted by SuperKoko
The 'output is undefined' camp seem to have gone quiet.
Any response to this, guys?
The order of evaluation of arguments is not defined. The compiler is allowed to do the various increments in any order it wishes as long as the appropriate one is done at the time the relevant function is entered. It could, if it wants, evaluate all of the increments in any order before entering the first function in the chain. The output is still undefined.
I should also point out that your original recast into functions is wrong.
The expression translates as:
So you can see that it is entirely possible for the compiler to plant the increments in any order it wishes prior to entering the first function call (and, therefore, sequence point).Code:operator<<(
operator<<(
operator<<(
operator<<(
operator<<(
operator<<(
operator<<(
cout, var1
)," "
), var1++
), " "
), ++var1
), " "
), var1++
);
THE OUTPUT IS UNDEFINED.
This stuff is pretty new to me too, but I believe the fact that they're nested function calls, rather than sequential ones, is what causes the problem. As a general example, consider an expression of the form:Quote:
Originally Posted by SuperKoko
Here we have two function calls Fn1 and Fn2, and three expressions Ex1 through Ex3. Those expressions may well be something of the form var1++ as in the original example.Code:Fn1( Fn2( Ex1, Ex2 ), Ex3 );
First we encounter a call to Fn1(). Before calling the function, its arguments must be evaluated. It is not defined which will be evaluated first: either the expression Ex3, or the call to Fn2(). Eventually Fn2() will be evaluated, but before it is, its own arguments must be evaluated. And again, it is not defined which will occur first: the evaluation of Ex1 or Ex2. In this way, only once all three expressions have been evaluated is the first function call made, and thus a sequence point encountered. It is conceivable that Ex1, Ex2, and Ex3 will be evaluated in any possible order.
If you want to confirm for yourself that this is indeed what's happening, compile the program from the original post and look at the assembly code the compiler generates. Here's what I got from VC++ 6.0 with optimizations off:
As you can see here, by the time any calls are made, the increments have all been performed, and all seven output characters (the four values plus pointers to three string literals) have been pushed onto the stack. So, if I understood the article right, there would have been no sequence points encountered at any time between the beginning of this line's evaluation and the time when all the arguments for all the function calls have been evaluated.Code:7: cout << var1 << " " << var1++ << " " << ++var1 << " " << var1++;
0040178F mov eax,dword ptr [ebp-4]
00401792 mov dword ptr [ebp-8],eax
00401795 mov ecx,dword ptr [ebp-8]
00401798 push ecx
00401799 mov edx,dword ptr [ebp-4]
0040179C add edx,1
0040179F mov dword ptr [ebp-4],edx
004017A2 push offset string " " (0046b01c)
004017A7 mov eax,dword ptr [ebp-4]
004017AA add eax,1
004017AD mov dword ptr [ebp-4],eax
004017B0 mov ecx,dword ptr [ebp-4]
004017B3 push ecx
004017B4 push offset string " " (0046b01c)
004017B9 mov edx,dword ptr [ebp-4]
004017BC mov dword ptr [ebp-0Ch],edx
004017BF mov eax,dword ptr [ebp-0Ch]
004017C2 push eax
004017C3 mov ecx,dword ptr [ebp-4]
004017C6 add ecx,1
004017C9 mov dword ptr [ebp-4],ecx
004017CC push offset string " " (0046b01c)
004017D1 mov edx,dword ptr [ebp-4]
004017D4 push edx
004017D5 mov ecx,offset std::cout (004767e0)
004017DA call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
004017DF push eax
004017E0 call @ILT+625(std::operator<<) (00401276)
004017E5 add esp,8
004017E8 mov ecx,eax
004017EA call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
004017EF push eax
004017F0 call @ILT+625(std::operator<<) (00401276)
004017F5 add esp,8
004017F8 mov ecx,eax
004017FA call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
004017FF push eax
00401800 call @ILT+625(std::operator<<) (00401276)
00401805 add esp,8
00401808 mov ecx,eax
0040180A call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
Thank you for that explanation. Very clear. :thumb:
I was thinking about this while trying to go to sleep and realized that I think I made an error in my last post, so here's a probably useless question/clarification:
Now that I think about it, in the example I gave, I think that Fn2() would be called once both Ex1 and Ex2 have been evaluated, meaning that several permutations still exist, but it's impossible or at least extremely unlikely for Ex3 to be evaluated between Ex1 and Ex2. That is, you could expect any of these four cases:Quote:
Originally Posted by Smasher/Devourer
Ex3
Ex1
Ex2
Fn2()
Fn1()
Ex3
Ex2
Ex1
Fn2()
Fn1()
Ex1
Ex2
Fn2()
Ex3
Fn1()
Ex2
Ex1
Fn2()
Ex3
Fn1()
But for Ex3 to be evaluated before Ex1 and after Ex2 doesn't seem likely. That would mean that in evaluating the arguments to Fn1() -- that is, Fn2(Ex1, Ex2) and Ex3 -- the program would have to start evaluating the first argument, then stop halfway through and evaluate the second, before completing its evaluation of the first. Is that right? Does the standard forbid something like this? Even if it doesn't, I sincerely doubt that a compiler would ever evaluate arguments in such a strange way. Anyone have a thought on this? Am I just spouting nonsense because I'm up too late?
In any case, I think the general spirit of my last post still stands, even if it's a bit rough around the edges. ;)
Thanks Smasher/Devourer for your very good posts.
And, yes of course there are nested function calls, and primarly i was thinking that because each function call depends of the previous and there is a sequence point between two function calls the result was defined... But that is false because parameter evaluation can be in any order, so finally the result is undefined.
You made all clear in my mind.
Thanks.
I really think that the standard allows that, even if very few compilers will do it.Quote:
Originally Posted by Smasher/Devourer
Because all side effects must be done before the function is called, but the funcion can be called after Ex3 has been evaluated (you know that well). And between two sequence points all side effects can occur in any order, really any order.
this Output is undfefined
totally depend on compiler behaviour
if u run same program on turbo C,Visual C,or gcc
each one is going to gave different output
depend how compiler treat them
Better to follow gcc logic
if two compiler follows all ANSI rule only then you can get same output
I know this topic has been beaten to death, but I was just reviewing my copy of "The C++ Standard Library" and Josuttis says the following with respect to a line with a long chain of stream outputs:
Quote:
"Thus,
is executed first. Note that the evaluative order of the operator does not imply any specific order in which the arguments are evaluated; only the order in which the operators are executed is defined.Code:std::cout << x