Разница в IL для ref-параметров - PullRequest
2 голосов
/ 01 мая 2019

Я пытаюсь понять разницу между тем, как параметры, передаваемые по ссылке и значению, обрабатываются на уровне IL.

Вот два метода в C #

    public static void TestRef(ref int x)
    {
        x++;
    }
    public static void Test(int x)
    {
        x++;
    }

Ниже указан IL для передачи по значению, я понимаю, что он загружает аргумент arg, затем константа int 1, добавляет его и заполняет егообратно в стек.

  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.1
  IL_0003:  add
  IL_0004:  starg.s    x
  IL_0006:  ret

IL для метода, который передается по ссылке:

IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.0
  IL_0003:  ldind.i4
  IL_0004:  ldc.i4.1
  IL_0005:  add
  IL_0006:  stind.i4
  IL_0007:  ret

Я не понимаю, почему существуют два оператора ldarg.0.Я предполагаю, что IL_0002 / 3 просто загружает адрес аргумента, а затем значение аргумента для этого адреса.

Но тогда как насчет IL_0001?Это как-то связано с левой стороной x =x+1?

1 Ответ

0 голосов
/ 01 мая 2019

Адрес, загруженный в IL_0001: ldarg.0, будет использован операцией сохранения в IL_0006: stind.i4.

MSDN сообщает нам о stind.i4 код операции:

Переходное поведение стека в последовательном порядке:

  1. Адрес помещается в стек.

  2. Значение помещается в стек.

  3. Значение и адрес извлекаются из стека; значение сохраняется по адресу.

https://docs.microsoft.com/de-de/dotnet/api/system.reflection.emit.opcodes.stind_i4?view=netframework-4.8

...