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

18.3Фиксированные и перемещаемые переменные

Оператор взятия адреса (§18.5.4) и оператор fixed (§18.6) разделяют переменные на две категории: фиксированные переменные и перемещаемые переменные.

Фиксированные переменные находятся в местах хранения, не затрагиваемых действием сборщика мусора (примерами фиксированных переменных являются локальные переменные, параметры по значению и переменные, созданные разыменованием указателей.) А перемещаемые переменные находятся в местах хранения, которые могут быть перемещены или удалены сборщиком мусора (примерами перемещаемых переменных являются поля в объектах и элементы массивов.)

Оператор & (§18.5.4) дает возможность без ограничений получать адрес фиксированной переменной. Но поскольку перемещаемая переменная может быть перемещена или удалена сборщиком мусора, адрес перемещаемой переменной можно получить только с помощью оператора fixed (§18.6), и этот адрес остается действительным только на время действия этого оператора fixed.

Точнее говоря, фиксированной переменной является одно из следующего:

  • переменная, полученная в результате простого_имени (§7.6.2), относящегося к локальной переменной или параметру по значению, если только эта переменная не захвачена анонимной функцией;

  • переменная, полученная в результате доступа_к_члену (§7.6.4) вида V.I, где V — фиксированная переменная типа_структуры;

  • переменная, полученная в результате выражения_косвенного_обращения_по_указателю (§18.5.1) вида *P, доступа_к_члену_по_указателю (§18.5.2) вида P->I или доступа_к_элементу_по_указателю (§18.5.3) вида P[E].

Все другие переменные классифицируются как перемещаемые.

Обратите внимание, что статическое поле классифицируется как перемещаемая переменная. Также обратите внимание, что параметр ref или out классифицируется как перемещаемая переменная, даже если аргумент, предоставленный для параметра, является фиксированной переменной. И наконец, обратите внимание, что переменная, созданная разыменованием указателя, всегда классифицируется как фиксированная переменная.

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

В небезопасном контексте набор доступных неявных преобразований (§6.1) расширен за счет включения следующих неявных преобразований указателей:

  • от любого типа_указателя к типу void*.

  • от литерала null к любому типу_указателя.

Кроме того, в небезопасном контексте набор доступных явных преобразований (§6.2) расширен за счет включения следующих явных преобразований указателей:

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

  • от типов sbyte, byte, short, ushort, int, uint, long и ulong к любому типу_указателя;

  • от любого типа_указателя к типам sbyte, byte, short, ushort, int, uint, long и ulong.

И наконец, в небезопасном контексте набор стандартных неявных преобразований (§6.3.1) включает следующее преобразование указателя:

  • от любого типа_указателя к типу void*.

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

При преобразовании одного типа указателя к другому, если полученный указатель неправильно выровнен для указываемого типа, поведение является неопределенным, если результат разыменован. В общем, понятие «правильно выровненный» является транзитивным: если указатель на тип A правильно выровнен для указателя на тип B, который в свою очередь правильно выровнен для указателя на тип C, то указатель на тип A правильно выровнен для указателя на тип C.

Рассмотрите следующий случай, когда доступ к переменной одного типа выполняется через указатель на другой тип:

char c = 'A'; char* pc = &c; void* pv = pc; int* pi = (int*)pv; int i = *pi; // undefined *pi = 123456; // undefined

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

using System;

class Test { unsafe static void Main() { double d = 123.456e23; unsafe { byte* pb = (byte*)&d; for (int i = 0; i < sizeof(double); ++i) Console.Write("{0:X2} ", *pb++); Console.WriteLine(); } } }

Конечно, производимый вывод зависит от порядка следования байтов.

Сопоставления между указателями и целыми определяются реализацией. Однако на архитектурах 32- и 64-разрядных ЦП с линейным адресным пространством преобразования указателей к целым типам и целых типов к указателям обычно происходит точно так же, как преобразования значений типа uint или ulong соответственно к этим целым типам или от них к указателям.

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