Оператор беззнакового сдвига вправо
Заметка
Эта статья является спецификацией компонентов. Спецификация служит проектным документом для функции. Он включает предлагаемые изменения спецификаций, а также информацию, необходимую во время проектирования и разработки функции. Эти статьи публикуются до тех пор, пока предложенные изменения спецификации не будут завершены и включены в текущую спецификацию ECMA.
Может возникнуть некоторое несоответствие между спецификацией компонентов и завершенной реализацией. Эти различия фиксируются в соответствующих собраниях по проектированию языка (LDM).
Дополнительные сведения о процессе внедрения спецификаций функций в стандарт языка C# см. в статье о спецификациях .
Сводка
Оператор сдвига вправо без знака будет поддерживаться C# как встроенный оператор (для примитивных целочисленных типов) и в качестве определённого пользователем оператора.
Мотивация
При работе с целочисленным значением со знаком нередко нужно сдвигать биты вправо, не копируя бит высокого порядка на каждом сдвиге. Хотя этого можно достичь для примитивных целочисленных типов с обычным оператором сдвига, требуется преобразование в неподписанный тип до операции сдвига и преобразование обратно после неё. В контексте универсальных математических интерфейсов, которые библиотеки планируют открывать, это может создать дополнительные сложности, так как тип может не иметь заранее определенного или известного аналога без знака в универсальном математическом коде, хотя алгоритм может зависеть от возможности выполнения операции сдвига вправо без учета знака.
Подробный дизайн
Операторы и пунктуаторы
Раздел §6.4.6 будет изменен, чтобы включить оператор беззнакового сдвига вправо >>>
.
unsigned_right_shift
: '>>>'
;
unsigned_right_shift_assignment
: '>>>='
;
Между маркерами в unsigned_right_shift и unsigned_right_shift_assignment продукциях не допускается никаких символов (даже пробелов). Эти построения обрабатываются особым образом, чтобы обеспечить правильную обработку списка параметров типа .
Операторы сдвига
Раздел §12.11 будет изменен, чтобы включить оператор >>>
— оператор без знака вправо:
Операторы <<
, >>
и >>>
используются для выполнения операций переключения битов.
shift_expression
: additive_expression
| shift_expression '<<' additive_expression
| shift_expression right_shift additive_expression
| shift_expression unsigned_right_shift additive_expression
;
Для операции формы x << count
или x >> count
или x >>> count
разрешение перегрузки двоичных операторов (§12.4.5) применяется для выбора конкретной реализации оператора. Операнды преобразуются в типы параметров выбранного оператора, а тип результата — возвращаемый тип оператора.
Предопределенные операторы смены без знака будут поддерживать тот же набор подписей, которые предопределенные операторы со знаком смены поддерживаются сегодня в текущей реализации.
Сдвиг вправо:
int operator >>>(int x, int count); uint operator >>>(uint x, int count); long operator >>>(long x, int count); ulong operator >>>(ulong x, int count); nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
Оператор
>>>
сдвигаетx
вправо на несколько битов, вычисляемых, как описано ниже.Младшие биты
x
отбрасываются, оставшиеся биты сдвигаются вправо, а позиции старших битов заполняются нулями.
Для предопределенных операторов число битов для смены вычисляется следующим образом:
- Если тип
x
являетсяint
илиuint
, число сдвигов определяется младшими пятью битамиcount
. Другими словами, количество сдвигов вычисляется изcount & 0x1F
. - Если тип
x
являетсяlong
илиulong
, число сдвигов задается шестью младшими битамиcount
. Другими словами, количество сдвигов вычисляется изcount & 0x3F
.
Если результирующее число сдвигов равно нулю, операторы сдвига просто возвращают значение x
.
Операции смены никогда не вызывают переполнения и создают те же результаты в checked
и unchecked
контекстах.
Операторы назначения
Раздел §12.21 будет изменен, чтобы включить unsigned_right_shift_assignment следующим образом:
assignment_operator
: '='
| '+='
| '-='
| '*='
| '/='
| '%='
| '&='
| '|='
| '^='
| '<<='
| right_shift_assignment
| unsigned_right_shift_assignment
;
Целочисленные типы
Целочисленные типы в разделе §8.3.6 будут изменены, чтобы включить сведения об операторе >>>
. Соответствующая точка маркера является следующей:
- Для двоичных
<<
операторов>>
и>>>
левый операнд преобразуется в типT
, гдеT
является первым изint
,uint
,long
иulong
, которые могут полностью представлять все возможные значения операнда. Затем операция выполняется с точностью типаT
, а тип результата —T
.
Константные выражения
Оператор >>>
будет добавлен в набор конструкций, разрешенных в константных выражениях §12.23.
Перегрузка оператора
Оператор >>>
будет добавлен в набор перегруженных двоичных операторов в §12.4.3.
Поднятые операторы
Оператор >>>
будет добавлен в набор двоичных операторов с поднятой формой в §12.4.8.
Приоритет оператора и ассоциативность
Раздел §12.4.2 будет изменен, чтобы добавить оператор >>>
в категорию "Сдвиг" и оператор >>>=
в категорию "Присваивание и лямбда-выражение".
Неоднозначность грамматики
Оператор >>>
подвергается той же неоднозначности грамматики, описанной в §6.2.5 как обычный оператор >>
.
Операторы
Раздел §15.10 будет отредактирован для включения оператора >>>
.
overloadable_binary_operator
: '+' | '-' | '*' | '/' | '%' | '&' | '|' | '^' | '<<'
| right_shift | unsigned_right_shift | '==' | '!=' | '>' | '<' | '>=' | '<='
;
Двоичные операторы
Подпись оператора >>>
применяется к тем же правилам, что и в §15.10.3 для подписи оператора >>
.
Имя метаданных
Раздел "I.10.3.2 Двоичные операторы" в ECMA-335 уже зарезервирован для оператора сдвига без знака вправо - op_UnsignedRightShift.
Деревья выражений Linq
Оператор >>>
не поддерживается в деревах выражений Linq, так как семантика предопределенных операторов >>>
для подписанных типов не может быть точно представлена без добавления преобразований в неподписанный тип и обратно. Дополнительные сведения см. в https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator.
Динамическая привязка
Похоже, что динамическая привязка использует элементы перечисления System.Linq.Expressions.ExpressionType для передачи информации о типе двоичного оператора привязке среды выполнения. Поскольку у нас нет элемента, специально представляющего оператор сдвига вправо без знака, динамическая привязка для оператора >>>
не будет поддерживаться, и раздел статической и динамической привязки (§12.3) будет изменён, чтобы отразить этот факт.
Недостатки
Альтернативы
Деревья выражений Linq
Оператор >>>
будет поддерживаться в деревьях выражений LINQ.
- Для определяемого пользователем оператора будет создан узел BinaryExpression, указывающий на метод оператора.
- Для предопределенных операторов
- Когда первый операнд является беззнаковым типом, будет создан узел BinaryExpression.
- Когда первый операнд является подписанным типом, преобразование первого операнда в неподписанный тип будет добавлено, будет создан узел BinaryExpression, и преобразование результата обратно в подписанный тип будет добавлено.
Например:
Expression<System.Func<int, int, int>> z = (x, y) => x >>> y; // (x, y) => Convert((Convert(x, UInt32) >> y), Int32)
Resolution:
Отклонено, см. https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator для получения дополнительной информации.
Неразрешенные вопросы
Дизайнерские встречи
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md
C# feature specifications