Программирование >>  Обработка исключительных ситуаций 

1 ... 112 113 114 [ 115 ] 116 117 118 ... 142


348 Глава 15. Дополнительные средства С#

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

Ключевое слово unsafe может использоваться либо как спецификатор, либо как оператор. В первом случае его указывают наряду с другими спецификаторами при описании класса, делегата, структуры, метода, поля и т. д. - везде, где допустимы другие спецификаторы. Это определяет небезопасный контекст для описываемого элемента, например:

public unsafe struct Node {

public int Value; . public Node* Left; public Node* Right;

Вся структура Node помечается как небезопасная, что делает возможным использование в ней указателей Left и Right. Можно применить и другой вариант описания, в котором небезопасными объявляются только соответствующие поля структуры:

public struct Node

public int Value; public, unsafe Node* Left; public unsafe Node* Right;

Оператор unsafe имеет следующий синтаксис: unsafe блок

Все операторы, входящие в блок, выполняются в небезопасном контексте.

ПРИМЕЧАНИЕ-

Компиляция кода, содержащего небезопасные фрагменты, должна производить! с ключом /unsafe. Этот режим можно установить путем настройки среды Visu Studio (Project Properties Configuration Properties Build Allow Unsafe Cod*

Синтаксис указателей

Указатели предназначены для хранения адресов областей памяти. Синтакс объявления указателя:

тип* переменная;

Здесь тип - это тип величины, на которую указывает пережиная, то есть ве. чины, хранящейся по записанному в переменной адресу. Тип не может 6i классом, но может быть структурой, перечислением, указателем, а также од*



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

из стандартных типов: sbyte, byte, short, ushort, int, uint, long, uiong, char, float, double, decimal, bool и void. Последнее означает, что указатель ссылается на переменную неизвестного типа.

Указатель на тип voi d применяется в тех случаях, когда конкретный тип объекта, адрес которого требуется хранить, не определен (например, если в одной и той же переменной в разные моменты времени требуется хранить адреса объектов различных типов).

Указателю на тип voi d можно присвоить значение указателя любого типа, а также сравнивать его с любыми указателями, но перед выполнением каких-либо действий с областью памяти, на которую он ссылается, требуется преобразовать его к конкретному типу явным образом. Примеры объявления указателей: int* а; указатель на int

Node* pNode; указатель на описанную ранее структуру Node

void* р; указатель на неопределенный тип

int*[] m; одномерн1й массив указателей на int

int** d; указатель на указатель на int

В одном операторе можно описать несколько указателей одного и того же типа, например:

int* а. Ь, с: три указателя на int

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

ПРИМЕЧАНИЕ-

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

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

Преобразования указателей

Для указателей поддерживаются неявные преобразования из любого типа указателя к типу void*. Любому указателю можно присвоить константу null. Кроме того, допускаются явные преобразования:

между указателями любого типа;

между указателями любого типа и целыми типами (со знаком и без знака).



350 Глава 15. Дополнительные средства С#

Корректность преобразований лежит на совести программиста. Преобразования

никак не влияют на величины, на которые ссылаются указатели, но при попытке

получения значения по указателю несоответствующего типа поведение програм-1

мы не определено .

Инициализация указателей

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

int а = 5: целая переменная

int* р = &а; в указатель запис1вается адрес а

ПРИМЕЧАНИЕ-

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

О с помощью значения другого инициализированного указателя: int* Г = р;

О с помощью имени массива, которое трактуется как адрес:

int[] b = new int[] {10. 20. 30, 50}; массив

fixed ( int* t = b ) { ... }; присваивание адреса начала массива fixed ( int* t = &b[0] ){...}; то самое

ПРИМЕЧАНИ Е-

Оператор f i xed рассматривается позже.

2 . Присваивание указателю адреса области памяти в явном виде:

char* V = (char *)0xl2F69E;

Здесь 0xl2F69E - шестнадцатеричная константа, (char *) - операция приведения типа: константа преобразуется к типу указателя на char.

ПРИМЕЧАНИЕ-

Использовать этот способ можно только в том случае, если адрес вам точно известен, в противном случае может возникнуть исключение.

3. Присваивание нулевого значения: i nt* хх = nul 1 :

1 Как правило, если в документации встречается оборот неопределенное поведение (undefined behavior), ничего хорошего это не сулит.



1 ... 112 113 114 [ 115 ] 116 117 118 ... 142

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика