Speak.Me Учить иностранные слова

C#: небезопасный код и указатели

C# поддерживает прямое управление памятью с помощью указателей в пределах блоков кода помеченных как небезопасный код и при условии компиляции с параметром /unsafe. Указатели могут быть полезны при работе с API написанными на C, а также для доступа к памяти вне управляемого хипа (heap) или особо критичных в плане производительности местах.

Основы указателей (Pointer)

Для каждого значимого или ссылочного типа V существует соответствующий указательный тип (pointer type) V*. Экземпляр указателя хранит адрес переменной. Указательный тип может быть приведен к любому другому указательному типу. Основными операторами для указателей являются:

  • & — оператор взятия адреса (address-of) — возвращает указатель на адрес переменной
  • * — оператор разыменования (dereference) — возвращает переменную по адресу указателя
  • -> — оператор указатель на член (pointer-to-member) — используется как сокращенный синтаксис: x->y эквивалент (*x).y

Небезопасный код

Если отметить тип, член типа или блок инструкций ключевым словом unsafe, то внутри их области видимости можно использовать указательные типы и выполнять операции в стиле указателей C++ для доступа к памяти:

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

Инструкция fixed

Инструкция fixed используется для того, чтобы закрепить управляемый объект, такой как bitmap в предыдущем примере. Во время выполнения программы многие объекты добавляются и удаляются из хипа. Чтобы избежать случайной потери или фрагментации памяти сборщик мусора передвигает объекты. Указатель на объект станет неверным если его адрес измениться пока указатель на него ссылается. Поэтому инструкция fixed заставляет сборщик мусора закрепить объект и не передвигать его. Это может отрицательно сказаться на производительности программы во время выполнения, поэтому зафиксированные блоки должны использоваться быстро.

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

Чтобы закрепить значимый тип, объявленный внутри ссылочного, необходимо закрепить этот ссылочный тип:

Оператор-указатель на член

В дополнение к операторам & и * C# позволяет использовать оператор -> в стиле C++. Он может быть использован для структур:

Ключевое слово stackalloc

Участок памяти, на который ссылается указатель, может быть размещен в стэке в виде массива с помощью ключевого слова stackalloc. В этом случае время его жизни будет ограничено временем выполнения метода, как для всех локальных переменных:

void*

Пустой указатель — void* — не устанавливает соглашений о типе данных, на которые ссылается указатель, поэтому он может быть использован для взаимодействия с необработанной памятью. Любой указательный тип может быть автоматически преобразован в void*void* не может быть разыменован (т.е. нельзя получить значение переменной по указателю), а также для него не доступны арифметические операции: