Search code examples
c#operatorsperformance

Is there any performance difference between ++i and i++ in C#?


Is there any performance difference between using something like

for(int i = 0; i < 10; i++) { ... }

and

for(int i = 0; i < 10; ++i) { ... }

or is the compiler able to optimize in such a way that they are equally fast in the case where they are functionally equivalent?

Edit: This was asked because I had a discussion with a co-worker about it, not because I think its a useful optimization in any practical sense. It is largely academic.


Solution

  • There is no difference in the generated intermediate code for ++i and i++ in this case. Given this program:

    class Program
    {
        const int counter = 1024 * 1024;
        static void Main(string[] args)
        {
            for (int i = 0; i < counter; ++i)
            {
                Console.WriteLine(i);
            }
    
            for (int i = 0; i < counter; i++)
            {
                Console.WriteLine(i);
            }
        }
    }
    

    The generated IL code is the same for both loops:

      IL_0000:  ldc.i4.0
      IL_0001:  stloc.0
      // Start of first loop
      IL_0002:  ldc.i4.0
      IL_0003:  stloc.0
      IL_0004:  br.s       IL_0010
      IL_0006:  ldloc.0
      IL_0007:  call       void [mscorlib]System.Console::WriteLine(int32)
      IL_000c:  ldloc.0
      IL_000d:  ldc.i4.1
      IL_000e:  add
      IL_000f:  stloc.0
      IL_0010:  ldloc.0
      IL_0011:  ldc.i4     0x100000
      IL_0016:  blt.s      IL_0006
      // Start of second loop
      IL_0018:  ldc.i4.0
      IL_0019:  stloc.0
      IL_001a:  br.s       IL_0026
      IL_001c:  ldloc.0
      IL_001d:  call       void [mscorlib]System.Console::WriteLine(int32)
      IL_0022:  ldloc.0
      IL_0023:  ldc.i4.1
      IL_0024:  add
      IL_0025:  stloc.0
      IL_0026:  ldloc.0
      IL_0027:  ldc.i4     0x100000
      IL_002c:  blt.s      IL_001c
      IL_002e:  ret
    

    That said, it's possible (although highly unlikely) that the JIT compiler can do some optimizations in certain contexts that will favor one version over the other. If there is such an optimization, though, it would likely only affect the final (or perhaps the first) iteration of a loop.

    In short, there will be no difference in the runtime of simple pre-increment or post-increment of the control variable in the looping construct that you've described.