Вход/Регистрация
ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
вернуться

Троелсен Эндрю

Шрифт:

Но все же, что не может не радовать, некоторые коды операций CIL в точности соответствуют их аналогам в C# (это, например, box, unbox, throw и sizeof). Вы сможете убедиться в том, что коды операций CIL всегда используются в контексте реализации члена и, в отличие от директив CIL, они никогда не обозначаются префиксом, заданным точкой.

Различия между мнемоникой и кодом операции CIL

Как только что объяснялось, коды операций, например ldstr, используются для реализации членов данного типа. Но в реальности лексемы (в том числе и ldstr) являются мнемониками CIL, представляющими на самом деле двоичные коды операций CIL. Чтобы пояснить различие, предположим, что у нас есть следующий метод, созданный средствами C#.

static int Add(int x, int у) {

 return х + у;

}

В терминах CIL сложение двух чисел представлено кодом операции 0X58. Аналогично для представления вычитания используется код операции 0X59, а действие, соответствующее размещению нового объекта в управляемой динамической памяти, обозначается кодом операции 0X73. С учетом сказанного должно быть ясно, что CIL-код, обрабатываемый JIT-компилятором, на самом деле является набором двоичных данных.

К счастью, для каждого двоичного кода операции CIL есть соответствующая мнемоника. Например, мнемоника add может использоваться вместо 0X58, sub – вместо 0X59, a newobj – вместо 0X73. Ввиду указанных различий между мнемониками и кодами операций, нетрудно догадаться, что декомпиляторы CIL, такие как, например, ildasm.exe, переводят двоичные коды операций компоновочного блока в соответствующую мнемонику CIL.

.method public hidebysig static int32 Add(int32 x, int32 y) cil managed {

 …

 // Лексема 'add' является более понятной мнемоникой CIL,

 // используемой для представления кода операции 0X58.

 add

 …

}

Тем, кто не сталкивается с необходимостью разработки низкоуровневого программного обеспечения .NET (например, пользовательского управляемого компилятора), обычно не приходится иметь дело непосредственно с числовыми кодами операций CIL. Поэтому практически всегда, когда программисты .NET говорят о "кодах операций CIL", они (как и я в этом тексте) имеют в виду набор более понятной мнемоники, а не лежащие в ее основе двоичные значения.

Добавление и извлечение данных: стековая природа CIL

Высокоуровневые языки .NET (например, такие как C#) пытаются максимально скрыть низкоуровневые сложности. Одним из аспектов разработки .NET, который оказывается скрытым особенно хорошо, является тот факт, что CIL является языком, целиком основанным на стековом программировании. Напомним, что при исследований пространства имен System.Collections (см. главу 7) мы с вами выяснили, что тип stack может использоваться для добавления значения в стек, а также для удаления из стека значения, размещенного на вершине стека. Конечно, разработчики CIL-приложений для загрузки и выгрузки значений не используют непосредственно объект System.Сollections.Stack, однако они применяют аналогичные операции.

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

В CIL просто невозможно получить доступ к элементам данных непосредственно, и это касается как локально определенных переменных, так и входных аргументов методов, а также полей данных типов. Нужно сначала явно загрузить элемент в стек, чтобы затем "вытолкнуть" его оттуда для дальнейшего использования (помните об этом, ведь именно поэтому блок программного кода CIL может казаться несколько избыточным).

Чтобы понять, как CIL использует стековую модель, рассмотрим простой C#-метод PrintMessage, который не имеет аргументов и ничего не возвращает. В рамках реализации этого метода вы просто выводите значение локальной строковой переменной в поток стандартного вывода.

public void PrintMessage {

 string myMessage = "Привет.";

 Consolе.WriteLine(myMessage);

}

Если рассмотреть результат трансляции этого метода компилятором C# в термины CIL, вы сразу заметите, что метод PrintMessage определяет ячейку хранения для локальной переменной, используя директиву.locals. Локальная строка затем загружается и сохраняется в этой локальной неременной с помощью кодов операций ldstr (загрузка строки) и stloc.0 (это можно прочитать, как "запомнить текущее значение в локальной переменной с индексом 0").

  • Читать дальше
  • 1
  • ...
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: