Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp Language Specification.doc
Скачиваний:
13
Добавлен:
26.09.2019
Размер:
4.75 Mб
Скачать

18.2Типы указателя

В небезопасном контексте тип (§4) может быть типом_указателя, а также типом_значений или ссылочным_типом. Однако тип_указателя можно также использовать в выражении typeof (§7.6.10.6) вне небезопасного контекста, так как такое использование не является небезопасным.

тип: ... тип_указателя

Тип_указателя записывается как неуправляемый_тип или как зарезервированное слово void с последующей лексемой *:

тип_указателя: неуправляемый_тип * void *

неуправляемый_тип: тип

Тип, указанный перед * в типе указателя, называется типом_референта типа указателя. Он представляет тип переменной, на которую указывает значение типа указателя.

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

Неуправляемый_тип — это любой тип, не являющийся ссылочным_типом или сформированным_типом и не содержащий поля ссылочного_типа или сформированного типа на любом уровне вложенности. Иначе говоря, неуправляемым_типом является один из следующих типов:

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal и bool;

  • любой перечисляемый_тип;

  • любой тип_указателя;

  • любой определенный пользователем тип_структуры, который не является сформированным типом и содержащий поля только неуправляемых_типов.

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

Примеры типов указателей приведены в следующей таблице:

Пример

Описание

byte*

указатель на byte

char*

указатель на char

int**

указатель на указатель на int

int*[]

одномерный массив указателей на int

void*

указатель на неизвестный тип

В данной реализации все типы указателей должны иметь одинаковый размер и представление.

В отличие от C и C++, если несколько указателей объявлены в одном объявлении, в C# звездочка * записывается только вместе с базовым типом, а не как префиксный знак пунктуации с каждым именем указателя. Например:

int* pi, pj; // NOT as int *pi, *pj;

Значение указателя, имеющего тип T* представляет адрес переменной типа T. Оператор косвенного обращения к указателю * (§18.5.1) можно использовать для доступа к этой переменной. Например, если дана

переменная P типа int*, то выражение *P означает переменную типа int, находящуюся по адресу, содержащемуся в P.

Как и ссылка на объект, указатель может иметь значение null. Результат применения оператора косвенного обращения к указателю со значением null зависит от реализации. Указатель со значением null представляется нулями во всех разрядах.

Тип void* представляет указатель на неизвестный тип. Поскольку тип референта неизвестен, оператор косвенного обращения нельзя применить к указателю типа void*, и с таким указателем нельзя выполнять никакие вычисления. Однако указатель типа void* можно привести к любому другому типу указателя (и наоборот).

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

Тип_указателя не может использоваться в качестве аргумента типа (§4.4), а вывод типа (§7.5.2) не работает при вызове универсальных методов, в процессе которого в качестве аргумента типа будет выведен тип указателя.

Тип_указателя можно использовать в качестве типа поля с модификатором volatile (§10.5.3).

Хотя указатели можно передавать в качестве параметров ref или out, это может привести к неопределенному поведению, поскольку указатель может быть установлен для указания на локальную переменную, которая больше не существует при возврате из вызванного метода, или если фиксированный объект, на который указывал указатель, больше не является фиксированным. Например:

using System;

class Test { static int value = 20;

unsafe static void F(out int* pi1, ref int* pi2) { int i = 10; pi1 = &i;

fixed (int* pj = &value) { // ... pi2 = pj; } }

static void Main() { int i = 10; unsafe { int* px1; int* px2 = &i;

F(out px1, ref px2);

Console.WriteLine("*px1 = {0}, *px2 = {1}", *px1, *px2); // undefined behavior } } }

Метод может возвращать значение некоторого типа, и этот тип может быть указателем. Например, если задан указатель на непрерывную последовательность элементов типа int, счетчика этой последовательности элементов и некоторого другого значения типа int, следующий метод возвратит адрес этого значения в этой последовательности, если есть соответствие, иначе возвращается null:

unsafe static int* Find(int* pi, int size, int value) { for (int i = 0; i < size; ++i) { if (*pi == value) return pi; ++pi; } return null; }

В небезопасном контексте имеется несколько конструкций для операций с указателями:

  • оператор * можно использовать для косвенного обращения к указателю (§18.5.1);

  • оператор -> можно использовать для доступа к члену структуры посредством указателя (§18.5.2);

  • оператор [] можно использовать для индексирования указателя (§18.5.3);

  • оператор & можно использовать для получения адреса переменной (§18.5.4);

  • операторы ++ и – можно использовать для увеличения и уменьшения указателей (§18.5.5);

  • операторы + и – можно использовать для выполнения арифметических операций с указателем (§18.5.6);

  • операторы ==, !=, <, >, <= и => можно использовать для сравнения указателей (§18.5.7);

  • оператор stackalloc можно использовать для выделения памяти из стека вызова (§18.7);

  • оператор fixed можно использовать для временной фиксации переменной, чтобы можно было получить ее адрес (§18.6).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]