Compartir a través de


Operador de desplazamiento a la derecha sin signo

Nota

Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos e se incorporan en la especificación ECMA actual.

Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.

Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C# en el artículo sobre las especificaciones de .

Problema planteado por experto: https://github.com/dotnet/csharplang/issues/4682

Resumen

C# admitirá un operador de desplazamiento a la derecha sin signo como operador incorporado (para tipos integrales primitivos) y como operador definido por el usuario.

Motivación

Cuando se trabaja con un valor integral con signo, no es raro que se necesite desplazar los bits hacia la derecha sin replicar el bit de orden superior en cada desplazamiento. Aunque esto se puede conseguir para tipos integrales primitivos con un operador de desplazamiento normal, se requiere un cambio a un tipo sin signo antes de la operación de desplazamiento y un cambio de vuelta después de la misma. En el contexto de las interfaces matemáticas genéricas que las bibliotecas están planeando exponer, esto es potencialmente más problemático ya que el tipo podría no tener necesariamente una contraparte sin signo definida o conocida de antemano por el código matemático genérico, sin embargo, un algoritmo podría depender de la capacidad de realizar una operación de desplazamiento a la derecha sin signo.

Diseño detallado

Operadores y signos de puntuación

La Sección 6.4.6 se ajustará para incluir el operador >>>: el operador de desplazamiento a la derecha sin signo:

unsigned_right_shift
    : '>>>'
    ;

unsigned_right_shift_assignment
    : '>>>='
    ;

No se permiten caracteres de ningún tipo (ni siquiera espacios en blanco) entre los tokens de unsigned_right_shift y las producciones de unsigned_right_shift_assignment. Estas producciones se tratan especialmente para permitir el control correcto de las type_parameter_list.

Operadores de desplazamiento

La Sección 12.11 se ajustará para incluir el operador >>>: el operador de desplazamiento a la derecha sin signo:

Los operadores <<, >> y >>> se usan para realizar operaciones de desplazamiento de bits.

shift_expression
    : additive_expression
    | shift_expression '<<' additive_expression
    | shift_expression right_shift additive_expression
    | shift_expression unsigned_right_shift additive_expression
    ;

Para una operación del formulario x << count o x >> count o x >>> count, la resolución de sobrecarga del operador binario (§12.4.5) se aplica para seleccionar una implementación de operador específica. Los operandos se convierten en los tipos de parámetro del operador seleccionado y el tipo del resultado es el tipo de valor devuelto del operador.

Los operadores de desplazamiento predefinidos sin signo admitirán el mismo conjunto de firmas que los operadores de desplazamiento predefinidos con signo admiten actualmente en la implementación actual.

  • Desplazamiento a la derecha:

    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);
    

    El operador >>> desplaza x hacia la derecha por un número de bits calculado según se describe a continuación.

    Los bits de orden bajo de x se descartan, los bits restantes se desplazan hacia la derecha y las posiciones de bits vacías de orden alto se establecen en cero.

Para los operadores predefinidos, el número de bits que se van a desplazar se calcula de la siguiente manera:

  • Cuando el tipo de x es int o uint, el recuento de desplazamientos lo proporcionan los cinco bits de orden bajo de count. En otras palabras, el recuento de turnos se calcula desde count & 0x1F.
  • Cuando el tipo de x es long o ulong, el recuento de desplazamientos lo proporcionan los seis bits de orden bajo de count. En otras palabras, el recuento de turnos se calcula desde count & 0x3F.

Si el recuento de desplazamientos resultante es cero, los operadores de desplazamiento simplemente devuelven el valor de x.

Las operaciones de desplazamiento nunca producen desbordamientos y generan los mismos resultados en contextos checked y unchecked.

Operadores de asignación

La Sección 12.21 se ajustará para incluir unsigned_right_shift_assignment de la siguiente manera:

assignment_operator
    : '='
    | '+='
    | '-='
    | '*='
    | '/='
    | '%='
    | '&='
    | '|='
    | '^='
    | '<<='
    | right_shift_assignment
    | unsigned_right_shift_assignment
    ;

Tipos enteros

Los tipos enteros Sección 8.3.6 se ajustarán para incluir información sobre el operador >>>. El punto de viñeta pertinente es el siguiente:

  • Para los operadores binarios <<, >> y >>>, el operando izquierdo se convierte en tipo T, donde T es el primero de int, uint, longy ulong que pueden representar completamente todos los valores posibles del operando. A continuación, la operación se realiza mediante la precisión de tipo Ty el tipo del resultado es T.

Expresiones constantes

El operador >>> se agregará al conjunto de construcciones permitidas en expresiones constantes en §12.23.

Sobrecarga del operador

El operador >>> se agregará al conjunto de operadores binarios sobrecargables en §12.4.3.

Operadores de elevación

El operador >>> se agregará al conjunto de operadores binarios que permiten un formulario elevado en §12.4.8.

Prioridad y asociatividad de los operadores

La sección §12.4.2 se ajustará para agregar el operador >>> a la categoría "Desplazamiento" y el operador >>>= a la categoría "Asignación y expresión lambda".

Ambigüedades gramaticales

El operador >>> está sujeto a las mismas ambigüedades gramaticales descritas en §6.2.5 como operador de >> normal.

Operadores

La sección §15.10 se ajustará para incluir al operador >>>.

overloadable_binary_operator
    : '+'   | '-'   | '*'   | '/'   | '%'   | '&'   | '|'   | '^'   | '<<'
    | right_shift | unsigned_right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='
    ;

Operadores binarios

La firma de un operador de >>> está sujeta a las mismas reglas que las de §15.10.3 para la firma de un operador de >>.

Nombre de la metadato

La sección "Operadores binarios I.10.3.2" de ECMA-335 ya reservó el nombre de un operador de desplazamiento a la derecha sin firmar: op_UnsignedRightShift.

Árboles de Expresión LINQ

El operador >>> no se admitirá en los Árboles de Expresión LINQ porque la semántica de los operadores predefinidos >>> en tipos con signo no se puede representar precisamente sin añadir conversiones a un tipo sin signo y de vuelta. Consulte https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator para obtener más información.

Vinculación dinámica

Parece que el enlace dinámico usa valores de la enumeración System.Linq.Expressions.ExpressionType para comunicar el tipo de operador binario al enlazador en tiempo de ejecución. Dado que no tenemos un miembro que represente específicamente un operador de desplazamiento a la derecha sin signo, no se admitirá la vinculación dinámica para el operador >>>, y se ajustará la sección de la vinculación estática y dinámica (Sección 12.3) para reflejarlo.

Inconvenientes

Alternativas

Árboles de Expresión Linq

El operador >>> será compatible con los árboles de expresiones Linq.

  • Para un operador definido por el usuario, se creará un nodo BinaryExpression que apunte al método de operador.
  • Para operadores predefinidos
    • cuando el primer operando es un tipo con signo, se creará un nodo BinaryExpression.
    • cuando el primer operando es un tipo con signo, se agregará una conversión para el primer operando a un tipo sin signo, se creará un nodo BinaryExpression y se agregará la conversión del resultado al tipo firmado.

Por ejemplo:

Expression<System.Func<int, int, int>> z = (x, y) => x >>> y; // (x, y) => Convert((Convert(x, UInt32) >> y), Int32)

Resolution:

Rechazado, consulte https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator para obtener más información.

Preguntas sin resolver

Reuniones de diseño

https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md