|
-
November 24th, 2003, 11:30 PM
#1
stupid basic C++ question...
I'm sure once someone explains this to me it will all seem rational but for right now the explanation for the following output escapes me...
#include <iostream>
int main(void) {
int i(0);
cout << i << ++i << i++ << endl;
}
output....
220
Why is it not 011?
The views expressed are those of the author and do not reflect any position taken by the Goverment of the United States of America, National Aeronautics and Space Administration (NASA), Jet Propulsion Laboratory (JPL), or California Institute of Technology (CalTech)
-
November 24th, 2003, 11:39 PM
#2
That is some very nasty code.
When I compiled it, it outputted "011", however I had to modify it.
1. You use the new C++ header (good job) but you didn't include the namespace, so it is impossible for you to use cout.
2. There is no need to pass void to int main().
Code:
#include <iostream>
using namespace std;
int main() {
int i(0);
cout << i << ++i << i++ << endl;
}
-
November 24th, 2003, 11:45 PM
#3
well
That code (after fixing the typos) will output either 220 or 011. Microsoft Visual C++ output 220 for me.
The reason is that the '<<' operator in the expression is a function call, and there is no standard for the order that a compiler evaluates expressions in functions calls. In one case the compiler evaluates them right to left, in the other case it is left to right.
Precedence of operators is defined in the C standard, but not evaluation order of function calls. Never depend on the order of evaluation when writing code, this is a perfect example of how it is compiler dependent.
-
November 24th, 2003, 11:46 PM
#4
Output of such code is compiler specific..........
so can be anything.............
-
November 24th, 2003, 11:46 PM
#5
yeah, yeah I forgot leading std:: for the example. Just add them and try it.
What I don't understand is why...
std::cout << i << ++i << i++ << std::endl;
output 220 (for me at least) while...
std::cout << i;
std::cout << ++i;
std::cout << i++ << std::endl;
outputs 011 as expected.
what are the rules for operator<< chaining that give such weird results. Yes, I could look it up in one of the Stroustrup bibles but I'm hoping for a more comprehensible answer here.
The views expressed are those of the author and do not reflect any position taken by the Goverment of the United States of America, National Aeronautics and Space Administration (NASA), Jet Propulsion Laboratory (JPL), or California Institute of Technology (CalTech)
-
November 24th, 2003, 11:56 PM
#6
Hei last u tried in seprate statements.
but how 220 will be the outout..
for cout<<i<<++i<<i++<<endl;
-
November 25th, 2003, 04:38 AM
#7
It's undefined behaviour.
You are not allowed to modify an entity more than once between sequence points. In your case the "++i" and the "i++" both attempt to modify i before you get to the sequence point (the semicolon at the end of the statement). Anything could happen - just think yourself lucky that it actually printed anyting at all.
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
November 25th, 2003, 06:47 AM
#8
mclark
At first I was very perplexed by this topic. Evidently, the behaior is not specified for the reason given by Graham.
There are several rational explainations as to why the compiler can come up with the 220 result.
Let's say it works right to left on the function calls and uses two intermediate registers, A and B, for the storage of i. OK the compiler puts i(0) into a CPU register A and stores it for later usage. Directly thereafter, a second CPU register B is used for intermediate storage of i. B is post incremented by the compiler. However, before calling the function operator<<(...), the compiler pre-increments B again. Finally then, the compiler calls the operator<<(...) three times using B, B and A. Thereafter the value of the intermediate register B is copied into A.
One thing is certain: After the execution of the entire line of code, the value of i will be 2.
The failure of C++ to define this behavior is unfortunately often a stumbling block for me and I wish it were otherwise. But there must be a good reason why it is the way it is, so I just switch off my brain and adhere to the specification.
Just my $0.02 worth.
Sincerely, Chris.
You're gonna go blind staring into that box all day.
-
November 25th, 2003, 07:44 AM
#9
dude i still think that answer is compiler dependent...........
-
November 25th, 2003, 07:51 AM
#10
The point is that the compiler is allowed to evaluate the expressions "i", "++i" and "i++" in any order it wants (as long as operator precedence rules are followed - not relevant in this example). You cannot tell the compiler to do it in a specific order (even by using parentheses). For example:
a = b + (c + d);
does not force the compiler to evaluate "c + d" first - it is allowed to evaluate "b + c" first and then add d if it so wishes.
In this case, there are six different ways that the compiler could evaluate the expressions - and they give different outputs.
For that reason, you cannot modify a single entity more than one between sequence points.
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
November 25th, 2003, 08:02 AM
#11
Hello,
Yes, the behavior is compiler dependent.
Yes the reasoning from Graham is correct.
and...
My description was added just in order to make plausible what a compiler might choose to do with the code sequence.
A very interesting post indeed.
BTW Graham, could you shed some light on the following: Does the inclusion of an operator precedence make some other sequences specified? I think that the operator precedence in another related example below will, in fact, force the compiler to compute c + d before multiplication with b and subsequent addition with a. However, if a were a subroutine a(...), then the temporal evaluation of a() in relation to b * (c + d) would not be specified. Please comment.
Code:
int result = a + b * (c + d);
Sincerely, Chris.
You're gonna go blind staring into that box all day.
-
November 25th, 2003, 01:26 PM
#12
It must evaluate both "b" and "c + d" before it can evaluate "b*(c + d)", but it could evaluate "a" at any time prior to evaluating the full expression. If it wanted, it could go:
"d", "b", "c" "c + d", "a", "b*(c + d)", "a + b*(c + d)".
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|