Стек - где хранится значение для типов значений? - PullRequest
3 голосов
/ 07 октября 2011
void main()
{
    int x = 5; // stack-allocated
    Console.WriteLine(x);
}

Мне известно, что x выделено в стеке.Но что на самом деле хранится в стеке около x?Содержит ли оно «реальное значение» или адрес какого-либо места в памяти, которое содержит значение?

Ответы [ 4 ]

8 голосов
/ 07 октября 2011

Ответ звучит громко: «это зависит».

Одно можно сказать наверняка: хранилище для локальной переменной x, если оно вообще существует, содержит действительное значение, а не ссылку, потому чтоint - это тип значения.

В переводе «без излишеств» мозговой фактическое значение x (не указатель или ссылка на него) сохраняется в локальной переменной в записи активации текущего вызова,Сгенерированный IL будет выглядеть примерно так:

  .maxstack 1
  .locals init (int32 V_0)

  ldc.i4.5  // push 5 on the evaluation stack
  stloc.0   // pop it into x

  ldloc.0   // now push a copy of x to pass to ...
  call void [mscorlib]System.Console::WriteLine(int32)

  ret       // return

(Обратите внимание, что директива .maxstack говорит о стеке оценки IL, не обязательно соответствующем собственному стеку. Стек оценки, если он неглубокий, равенчасто хранится в регистрах с помощью JIT-скомпилированного кода.)

В большинстве современных реализаций CLR записи активации и их локальные переменные будут храниться в собственном стеке.Таким образом, наивно, я полагаю, что x можно было бы считать хранящимся в стеке его значением.

В оптимизирующей компиляции (или оптимизирующей JIT-трансляции) приведенного выше кода хранилище локальных переменных не может существоватьв ил вообще.В конце концов, зачем выделять локальную переменную для хранения, а затем тратить две инструкции, играя с этой локальной переменной, когда она вам больше никогда не понадобится?Его можно указать как постоянный параметр для WriteLine:

  .maxstack 1
  // Just pass 5 to WriteLine.  No local variables here.
  ldc.i4.5
  call void [mscorlib]System.Console::WriteLine(int32)
  // Bye.
  ret

Возможны и другие осложнения.Если функция была объявлена ​​async как в C # 5 CTP, или если x были захвачены лямбда-выражением в другом месте функции, или если функция была перечислителем, созданным с помощью оператора yield return, хранилище для x может в конечном итоге оказаться в куче: оно станет полем в классе, сгенерированном компилятором, так что хранилище переменной сможет пережить разрушение стекового фрейма, если замыкание или продолжение ускользает от локальной области видимости.

0 голосов
/ 07 октября 2011

Вероятно, поскольку размер байта int будет меньше или равен размеру регистра вашего процессора, трудно предсказать ситуацию, когда CLR решит поступить иначе.

Однако, хотя это может представлять академический интерес, это не нужно учитывать при написании программы на C #. Его детали реализации, он может измениться, код все еще будет работать. Реализаторы CLR освободили нас от этой ответственности.

0 голосов
/ 07 октября 2011

Полагаю, эта строка переведена в команду ldind.i.Спецификация гласит:

4D ldind.i Загружает собственное значение типа int по адресу addr в стек как собственное значение типа int.

0 голосов
/ 07 октября 2011

Хранит реальное значение х. Там нет адреса или что-то еще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...