3

I was wondering: how is the C# array indexer implemented? You can index a C# array with basically every integer value from ulong to sbyte, does the internal implementation simply casts to a common type every time?

To be clear will this:

ulong i = 10;
var o = myArray[i];

be translated into something like:

ulong i =10;
var o = myArray[(int /*or whatver is the default type used*/)i];

?

adjan
  • 13,371
  • 2
  • 31
  • 48
Alakanu
  • 325
  • 2
  • 11
  • 3
    [Enjoy](https://referencesource.microsoft.com/#mscorlib/system/array.cs) – Zohar Peled Oct 18 '18 at 10:31
  • 2
    good luck finding that in the source code. – Selman Genç Oct 18 '18 at 10:32
  • 2
    @Zohar: You should probably link to the implementation of the IL instructions in the JIT, as that's what's happening there, and not a method call on `System.Array`. – Joey Oct 18 '18 at 10:40
  • Note that the check is not actually alwas executed. The JiT and general IL optimsiations can really help keeping the load low: https://blogs.msdn.microsoft.com/clrcodegeneration/2009/08/13/array-bounds-check-elimination-in-the-clr/ – Christopher Oct 18 '18 at 10:41
  • Thanks everyone! – Alakanu Oct 18 '18 at 11:39

1 Answers1

5

The type of an array indexer is integer, so yes, the value will be converted to int. You can verify this by examining the IL code. Given this example:

var myArray = new[]{ 1,2,3 };
ulong i = 10;
var o = myArray[i];

This will compile into:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       29 (0x1d)
  .maxstack  3
  .locals init ([0] int32[] myArray,
           [1] uint64 i,
           [2] int32 o)
  IL_0000:  nop
  IL_0001:  ldc.i4.3
  IL_0002:  newarr     [mscorlib]System.Int32
  IL_0007:  dup
  IL_0008:  ldtoken    field valuetype '<PrivateImplementationDetails>'/'__StaticArrayInitTypeSize=12' '<PrivateImplementationDetails>'::E429CCA3F703A39CC5954A6572FEC9086135B34E
  IL_000d:  call       void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array,
                                                                                                      valuetype [mscorlib]System.RuntimeFieldHandle)
  IL_0012:  stloc.0
  IL_0013:  ldc.i4.s   10
  IL_0015:  conv.i8
  IL_0016:  stloc.1
  IL_0017:  ldloc.0
  IL_0018:  ldloc.1
  IL_0019:  conv.ovf.i.un
  IL_001a:  ldelem.i4
  IL_001b:  stloc.2
  IL_001c:  ret
} // end of method Program::Main

The conversion happens at IL_0019 with conv.ovf.i.un instruction.

Converts the unsigned value on top of the evaluation stack to signed native int, throwing OverflowException on overflow.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • An easy way to show IL for your code is https://SharpLab.io - for the curious reader of this answer. – AndreasHassing Oct 18 '18 at 11:05
  • Thank you! I did try SharpLab.io before asking but I still can't understand IL very well, this is why I've asked the question :) – Alakanu Oct 18 '18 at 11:40
  • I know that this answer will stay the same but if you want to 'proof' this kind of question with IL you will need to repeat this with forced x64 and x32 platforms, optimization on/off, ... . You didn't even mention your settings. I always prefer a specification. – bommelding Oct 18 '18 at 11:51