2011-10-19 21 views
9

¿Hay alguien que pueda explicarme este extraño comportamiento?¿Por qué debería rodear explícitamente con "desmarcado"?

int i = 0x1234; 
    byte b1 = (byte)i; 
    byte b2 = (byte)0x1234;   //error: const value '4660' can't convert to byte (use unchecked) 
    byte b3 = unchecked((byte)0x1234); 
    byte b4 = checked((byte)i);  //throws 
    byte b5 = (byte)(int)0x1234; //error: same as above 

NOTA: Es una aplicación vacía de la consola, con NO aritmética comprobación habilitada (por defecto es). Gracias a todos de antemano.

EDIT: Supuse que era lo suficientemente claro, pero no para todos.

Sé que una palabra no cabe en un byte. Pero, de forma predeterminada, un programa C# permite ciertas operaciones "peligrosas", principalmente por motivos de rendimiento.

Del mismo modo, puedo sumar dos enteros grandes juntos y sin desbordamiento alguno.

Me sorprendió el error de tiempo de compilación anterior: el reparto/asignación b1 está compilado, el b2 no se puede compilar. Aparentemente no hay diferencia, porque ambos tienen Int32 teniendo el mismo valor.

Espero que esté claro ahora.

+3

No hablo C# y no sé lo que significa "comprobado" y "no marcado", pero sé que no puede caber un número hexadecimal de cuatro dígitos en un byte. –

+1

¿Qué comportamiento es "extraño" para ti? Nos ha dado ** pasos para reproducir ** y ** resultado real **, pero no ** resultado esperado **. – AakashM

Respuesta

11

Estás tropezar con una parte de la sección 7.19 de la C# 4 especificaciones:

A menos que una expresión constante se coloca de forma explícita en un contexto unchecked, desbordamientos que se producen en las operaciones y conversiones aritméticas de tipo integral durante la evaluación en tiempo de compilación de la expresión siempre causa errores en tiempo de compilación.

Básicamente, el punto es que incluso si usted está de acuerdo en permitir el desbordamiento de las operaciones en ejecución tiempo, si usted está tratando de utilizar una expresión constante que no se puede convertir al tipo de destino en tiempo de compilación, tiene que decirle al compilador que realmente sabe lo que está haciendo.

Por ejemplo, en este caso estamos perdiendo información - que va a ser equivalente a

byte b3 = 0x34; 

por lo que tendría normalmente ser mejor simplemente especificando que, para darle código más claro, que doesn engañar al lector Es relativamente raro que desee desbordar en una constante; la mayoría de las veces, solo debe especificar el valor válido.

+3

Parece un abogado citando la _ "sección 7.19 de la especificación C# 4" _. : D – Otiel

+0

Para mí, eso está bien, pero ¿por qué el compilador no tiene en cuenta también el desbordamiento aritmético? Gracias de todos modos: fue solo una curiosidad con la que me topé. –

+0

@MarioVernari: Porque está diseñado para cambiar el comportamiento del tiempo de ejecución, la mayoría del código C# probablemente esté construido con ese valor predeterminado, pero a la mayoría de los desarrolladores todavía les debe importar si sus * constantes * se desbordan. –

1

Esto no es un comportamiento extraño, el rango válido para una variable del tipo de datos es byte0-255, pero cuando se convierte HEX 0x1234 valor en sistema decimal que tiene 4660. Así que unchecked se usa para controlar las operaciones y conversiones aritméticas de tipo integral de comprobación de desbordamiento.

Puede encontrar que unchecked de uso frecuente en la implementación GetHashCode() que realiza operaciones numéricas para calcular el código hash final.

Para resumir, debe usar unchecked cuando el valor de resultado final de las operaciones de tipo entero no es importante, pero puede ocurrir un desbordamiento.

1

Usted no debería rodear esto con unchecked.Desmarcado permite la asignación de tipos de valores peligrosos a un tipo, que puede causar desbordamientos.

byte b1 = (byte)i; causará una excepción de desbordamiento o lanzamiento durante el tiempo de ejecución.

byte b2 = (byte)0x1234; no es válido porque no puede almacenar valores mayores que 0xFF en un byte.

byte b3 = unchecked((byte)0x1234); colocará 0x34 o 0x12 (según la implementación de CLR) en b3, y el otro byte se desbordará.

byte b4 = checked((byte)i); es lo mismo que byte b1 = (byte)i;

byte b5 = (byte)(int)0x1234; proyectará 0x1234 a un int, y luego tratar de echarlo a byte. De nuevo, no puede convertir 0x1234 en un byte porque es demasiado grande.

+0

Bueno, tienes razón en parte, pero no en absoluto. Es cierto que evitar los controles es una práctica peligrosa, pero también debes usarlos con un poco de cerebro, en mi humilde opinión. NO es cierto, su primera asignación causa una excepción. Lanzará solo si habilita la "comprobación aritmética" (el valor predeterminado es desactivado). La tercera tarea que supongo que es incorrecta: debe devolver siempre 0x12. Cuarto: las mismas consideraciones del primero. Quinto: igual que el segundo. Cheers –

+0

La tercera siempre devolverá 0x34, no 0x12. Y el primero solo causará una excepción si la verificación está habilitada Y si el valor está fuera del rango 0-255. – phoog

+0

Gracias por las correcciones chicos :) – Polynomial

Cuestiones relacionadas