Thursday, August 25, 2011

int i = 0; i = i++; /* How to Make Your Friends and Co-workers Scratch Their Heads in Less than 2 lines of Code */

Looking for a great way to kill productivity (stop! and get back to work!!! ;) )? Want to stump that developer who thinks they've seen it all? Well then have I got the code snippet for you!
(sorry - I felt the need to sound like an info-mercial salesman there for no good reason)...

Don't ask how this problem came up... It was one of those things that started off as a joke, but then got people thinking and scratching their heads...

Consider the following code snippet:

int i = 0;
i = i++;
/* output 1 if Java use System.out.println(i); if C/C++ use printf(%d,i); */
i = ++i;
/* output 2 if Java use System.out.println(i); if C/C++ use printf(%d,i); */

Seems pretty simple doesn't it? I bet though, that if you ask a handful of developers what the output on 1 & 2 would be, that you'd get some pretty interesting answers. This tiny little code snippet turned into a long discussion on more than one occasion. When actually run, most assumptions were wrong and many were stumped.
I suggest trying it yourself in your language of choice if your curious! You might be surprised too!... The TRULY surprising part might be that your language of choice might provide you with one answer when compiled with one compiler version, and another result when the same code is compiled using a different version.

Since this all came about in a Java shop, I immediately went ahead and ran it -
0 , 1 (yeah - I spoiled the surprise... sorry)
Wishing to get some clarification on what was going on, I surfed the web and found some help here.

It seems like (under the hood), that this:
int i = 0;
i = i++;

basically translates to this:
int i = 0;
int temp = i;
i = temp;

that is, since we're post incrementing on the right hand side of the above, that the expression is evaluated and stored in "temp", i is incremented, then the assignment occurs to the initially stored value... (thats what the above link seemed to point out...)

This seemed logical and explained the resulting values.

So I tried it out in C. I went ahead and wrote up the snippet and compiled with GCC version 3.something or other.
output- same as Java. 0,1.

So, I took the above explanation as a decent one that seemed to be applicable to both Java and C/C++...
Then the wheels fell off of the wagon. A buddy of mine and I were chatting when I brought up the above mentioned problem. Being the curious chap he is, he went and tried the same.
In C, using GCC, but this time version 4.2.something or other.
output... TOTALLY DIFFERENT! 1,2.

So I let out a big sigh. Back to finding answers...

The jury's still out on this one for me. Now on my TODO list is trying to determine where and how this is defined (or if it is!).
I recently came across a site that might point to this being undefined in C/C++ (found here)
But since you can't trust everything you read on the internet (except the stuff I write :) ) I'd like to find a "more offical" source if I can.

I know its a trivial thing, but its one of those trivial things thats gotten under my skin and that I now want to know the answer to.
I know the code looks trivial too... but there is some pretty gnarly looking code out there in the wild and who know's if anyone is doing something like this (or similar):
i = (someCrazyFunction() + 1) / i++; /* threw in the 1 for good measure! */

I guess the best thing I've gotten out of this is that... just because you think you know what the compiler is going to do, doesn't mean that the compiler is going to do that. So often we take whats going on under the hood for granted. Abstraction is a great thing and helps us crank out code faster and build bigger and better (okay... thats arguable) things. If we're going to operate within an abstraction though, we should have an understanding of not only what that abstraction provides us but also its limitations...

No comments:

Post a Comment