I was asked a question that sounds simple but it's a bit tricky. What's the output of following C# code?
public class Program
{
static void Main(string[] args)
{
int i = 0; i = i++;
int j = 0; j = ++j;
Console.WriteLine("{0} {1}", i, j);
Console.Read();
}
}
I thought it's "1 1" but I was wrong. The correct answer is "0 1".
Why? i++ is an after operation, so a temporary value is created to store the before and after value. The explanation is not that straightforward. Let's look at the IL code generated by compiler, and see what's under the hood:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 47 (0x2f)
.maxstack 3
.locals init (int32 V_0,
int32 V_1)
IL_0000: nop
// i operation
IL_0001: ldc.i4.0 // Put constant number 0 onto the stack
IL_0002: stloc.0 // Pop from the stack and store it in the local variable #0 (number = 0)
IL_0003: ldloc.0 // Push local variable #0 onto the stack
IL_0004: dup // Duplicate the value in the stack (push another 0 onto stack)
IL_0005: ldc.i4.1 // Put constant number 1 onto the stack
IL_0006: add // Pop last two values from stack and push back their sum (1+0=1)
IL_0007: stloc.0 // Pop from stack and store it to local variable #0 (number=1)
IL_0008: stloc.0 // Pop from stack and store it to local variable #0 (overwritten number=0)
// j operation
IL_0009: ldc.i4.0 // put constant number 0 onto the stack
IL_000a: stloc.1 // Pop from the stack and store it in the local variable #1 (number=0)
IL_000b: ldloc.1 // Push local variable #1 onto the stack
IL_000c: ldc.i4.1 // Put constant number 1 on the stack
IL_000d: add // Pop last two values from stack and push back their sum (1+0=1)
IL_000e: dup // Duplicate the value in the stack (push another 1 onto stack)
IL_000f: stloc.1 // Pop from the stack and store it to local variable #1 (number=1)
IL_0010: stloc.1 // Pop from the stack and store it to local variable #1 (number=1)
// Print
IL_0011: ldstr "{0} {1}"
IL_0016: ldloc.0 // Load local variable #0 (0) onto stack
IL_0017: box [mscorlib]System.Int32
IL_001c: ldloc.1 // Load local variable #1 (1) onto stack
IL_001d: box [mscorlib]System.Int32
IL_0022: call void [mscorlib]System.Console::WriteLine(string,
object,
object)
IL_0027: nop
IL_0028: call int32 [mscorlib]System.Console::Read()
IL_002d: pop
IL_002e: ret
} // end of method Program1::Main
We can see that the plus operation is run in a separate stack, the result of 1 is assigned to the local variable, but is overwritten by original value of 0. Thus the original i value of 0 is used for the assignment of i = i++. Is it ambiguous? I'm not sure. It's the way how .NET deals with such scenarios.
(Updated Jan 7, 07) I tested in Java (1.5) and got the same result of "0 1". But in C++ (compiled by VS.NET 2005) it returns "1 1".