programming guide c# language-design

guide - doc c#



¿Por qué se define la implementación de la especificación de C#(int.MinValue/-1)? (2)

Este es un efecto secundario del hermano mayor de la Especificación de lenguaje C #, Ecma-335 , la especificación de la infraestructura de lenguaje común. La sección III, capítulo 3.31 describe lo que hace el código de operación DIV. Una especificación que la especificación de C # muy a menudo tiene que diferir, bastante inevitable. Especifica que puede tirar pero no lo demanda.

De lo contrario una evaluación realista de lo que hacen los procesadores reales. Y el que todo el mundo usa es el raro. Los procesadores Intel son excesivamente peculiares sobre el comportamiento de desbordamiento, fueron diseñados en la década de 1970 con el supuesto de que todos usarían la instrucción INTO. Nadie lo hace, una historia para otro día. Sin embargo, no ignora el desbordamiento en un IDIV y eleva la trampa #DE, no puede ignorar ese fuerte golpe.

Bastante difícil de escribir una especificación de lenguaje encima de una especificación de tiempo de ejecución lanudo además de un comportamiento inconsistente del procesador. Poco que el equipo de C # podría hacer con eso pero reenviar el lenguaje impreciso. Ya fueron más allá de la especificación al documentar OverflowException en lugar de ArithmeticException. Muy travieso. Tenían un vistazo.

Un vistazo que reveló la práctica. Es muy poco probable que sea un problema, el jitter decide si está en línea o no. Y la versión no en línea lanza, la expectativa es que la versión en línea lo hace también. Nadie ha sido decepcionado todavía.

La expresión int.Minvalue / -1 da como resultado un comportamiento definido de implementación de acuerdo con la especificación de C #:

7.8.2 operador de la división

Si el operando izquierdo es el valor representable int o long más pequeño y el operando derecho es -1, se produce un desbordamiento. En un contexto comprobado, esto hace que se lance una excepción System.ArithmeticException (o una subclase del mismo). En un contexto no verificado, se define por la implementación si se emite una excepción System.ArithmeticException (o una subclase de la misma) o si el desbordamiento no se reporta, y el valor resultante es el del operando izquierdo.

Programa de prueba:

var x = int.MinValue; var y = -1; Console.WriteLine(unchecked(x / y));

Esto genera una OverflowException en .NET 4.5 de 32 bits, pero no tiene que hacerlo.

¿Por qué la especificación deja el resultado definido por la implementación? Aquí está el caso en contra de hacer eso:

  1. La instrucción idiv x86 siempre produce una excepción en este caso.
  2. En otras plataformas, podría ser necesaria una verificación de tiempo de ejecución para emular esto. Pero el costo de esa verificación sería bajo en comparación con el costo de la división. La división entera es extremadamente costosa (15-30 ciclos).
  3. Esto abre riesgos de compatibilidad ("escribir una vez ejecutarse en ninguna parte").
  4. Desarrollador sorpresa.

También es interesante el hecho de que si x / y es una constante de tiempo de compilación, de hecho, nos unchecked(int.MinValue / -1) == int.MinValue :

Console.WriteLine(unchecked(int.MinValue / -1)); //-2147483648

Esto significa que x / y puede tener diferentes comportamientos dependiendo de la forma sintáctica que se esté utilizando (y no solo dependiendo de los valores de x e y ). Esto está permitido por la especificación, pero parece una elección imprudente. ¿Por qué C # fue diseñado de esta manera?

Una pregunta similar indica en qué parte de la especificación se prescribe este comportamiento exacto, pero no responde (suficientemente) por qué el lenguaje fue diseñado de esta manera. Las opciones alternativas no se discuten.


Un objetivo principal de diseño de C # es supuestamente "Ley de sorpresa mínima". De acuerdo con esta guía, el compilador no debe intentar adivinar la intención del programador, sino que debe indicar al programador que se necesita una guía adicional para especificar correctamente la intención. Esto se aplica al caso de interés porque, dentro de las limitaciones de la aritmética de complemento a dos , la operación resulta en un resultado muy sorprendente: Int32.MinValue / -1 se evalúa como Int32.MinValue . Se ha producido un desbordamiento y se requerirá un 33''rd bit no disponible, de 0, para representar correctamente el valor correcto de Int32.MaxValue + 1 .

Como se esperaba, y como se indica en su cotización, en un contexto marcado, se genera una excepción para alertar al programador sobre la falla en especificar correctamente la intención. En un contexto no verificado, se permite que la implementación se comporte como en el contexto comprobado, o que permita el desbordamiento y devuelva el resultado sorprendente. Hay ciertos contextos, como el twiddling de bits, en los que es conveniente trabajar con int firmados, pero donde el comportamiento de desbordamiento es realmente esperado y deseado. Al revisar las notas de implementación, el programador puede determinar si este comportamiento es realmente el esperado .