Programming Puzzel For You All

Recommended Posts

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;

int main()
{
int i = 1;
int k = (++i)+(++i)+(++i);
cout << k << endl;
return 0;
}


Then evaluate the same thing in any compiler of your choice and check the output. Post what you thought and what you got, along with compiler used. [grin] Feel free to try other languages as well, this is quite intresting.

Share on other sites
9? In my head, no checking.

Share on other sites
Interesting... Not 9.

Share on other sites
I thought I was going to get 9 and I got 12 with VS 2003 and 10 with g++ (GCC) 3.3.5 (Debian 1:3.3.5-13)

Share on other sites
Huh. I got 9 in my head as well, and then GCC says 10.

How did that happen?

Share on other sites
Modifying a variable several times in between code points has undefined behaviour.

int k = (++i)+(++i)+(++i); is neither valid C nor C++.

Share on other sites
One would hope that would generate an error or at least a warning if it's not valid C/C++...

Share on other sites
Quote:
 Original post by MauManI thought I was going to get 9 and I got 12 with VS 2003 and 10 with g++ (GCC) 3.3.5 (Debian 1:3.3.5-13)

That is because it is undefined behaviour.

you could do this,
i=1;i+=i++++i++i+i++i++;

And the result would be different from compiler to compiler.

Share on other sites
now that's just sloppy code.

Share on other sites
Got 9 with J2SDK 1.4.2_06 and in my tiny head too which now hurts.

Share on other sites
Intel C++ compiler v8.1 gave 9

Share on other sites
A better (maybe fun) question might be to speculate why

VS gave 12
GCC gave 10
JRE (java) gave 9

:)

Share on other sites
I think it's 6...

Share on other sites
I think the reason gcc gives 10 is something like this: it parses the (++i)+(++i)+(++i) expression into a tree and then executes the left side, followed by the right side, of each node to give the final result.

Hence the order of execution looks like:
++i;
++i; /* Left/right of first + */
tmp = i + i;
++i;
tmp += i;

I think it would be straightforward to modify gcc to give "correct" (as in giving 9) behaviour, but it isn't required by the standard and this way optimises marginally better.

Share on other sites
It evaluates to wrong. Wrong wrong wrong!

Anyway..... wouldnt it be better for the compiler to give an error when someone tries to do something like this?

Share on other sites
Quote:
 Original post by greksterAnyway..... wouldnt it be better for the compiler to give an error when someone tries to do something like this?

I guess back in 1989 that kind of dependency tracking was too complicated to require in the standard. IMHO Java-like behaviour should be required because I can't really see it actually slowing anything down.

Share on other sites
I wonder why GCC uses a temporary in this case.

VS gives 12 with something like the following
(in psuedo asm)

inc a;
inc a;
inc a;

I guess VS must do instruction selection differently then GCC.

In any case, it's stupid to write (++i) + (++i) + (++i). So the standard is perfectly fine with undefined behaviour.

Share on other sites
I was just using the temporary variable for illustrative purposes. My point was that's how the code is initially converted into gccs internal representation which is why it gives 10 (since it's using what looks to me like the simplest parsing system). The MS compiler would seem to be evaluating all side effects first so it gives 12.

Share on other sites
it's easy. By standard this code:
int v = 0; std::cout << v+++v++;
results in undefined behaviour. Cause you cannot access on the same statement two time over a post-incremented variable.
My signature on italian forum was (for years)

do you think that C++ is an easy language?
int v = 0; std::cout << v+++v++;

it was a question that one person ask me when I begin my first programming-related work.

Share on other sites
Another one :) What shall this one print, was brought up by friend of mine some time ago:
void AddVertex( float x, float y, float z ){	printf( "x:%f, y:%f, z:%f\n", x, y, z );}int _tmain(int argc, _TCHAR* argv[]){	float	verts[] =	{		1, 2, 3,		4, 5, 6,		7, 8, 9,		10, 11, 12,	};	const size_t nVerts = 4;	float*	ptr = &verts[0];	for( size_t i = 0; i < nVerts; i++ )		AddVertex( *ptr++, *ptr++, *ptr++ );	getchar();	return 0;}

the code thing fails to show the *ptr<plus><plus> correctly...

Share on other sites
Parameter evaluation order is undefined.

Share on other sites
I actually got bitten by this, believe it or not. Didn't take me long to realise what had gone wrong though.

You see, I was writing a (stupid, testing) virtual machine. I had some bytecode that was just a big array of ints. So, I wen't like this:
for(int i = 0; i < arraySize; ++i){   switch(byteCode[i])   {      case Foo:         Foo(byteCode[++i], byteCode[++i]); //Ouch, wrong parameters.         break;   }}

Share on other sites
Quote:
 Original post by memonthe code thing fails to show the *ptr correctly...

It's not supposed to do what you think. One of the sequence points in C++ is:

after evaluation of all a function's parameters but before the first expression within the function is executed

So you dereference the first float in verts[] 3 times and pass those identical values to AddVertex. Before the printf statement ptr gets incremented 3 times and points to the 4th element.

Share on other sites
"The only place that cleverness comes before correctness is the dictionary."

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

• Forum Statistics

• Total Topics
628301
• Total Posts
2981914

• 10
• 11
• 11
• 10
• 10