2008-10-26 8 views
12

Cuando intenta declarar una variable sin firmar en C# .NET con un valor fuera de su rango de valores, se marca como un error del compilador, pero si genera un valor negativo en tiempo de ejecución y lo asigna a ese variable en tiempo de ejecución el valor se ajusta.Diferencia de dos 'uint'

uint z = -1; // Will not compile 

uint a = 5; 
uint b = 6; 
uint c = a - b; // Will result in uint.MaxValue 

¿Existe una buena razón para que las variables sin firmar se envuelvan en una situación así en lugar de arrojar una excepción?

Gracias.

+0

Lo mismo vale para ulong – Llyle

Respuesta

26

Declarar una variable no asignada en C# no se marca con un error; es un error intentar asignar un valor no válido a una variable. Por ejemplo, aquí es una variable que no está definitivamente asignado (asumiendo que es local) después de la declaración:

uint z; 

-1 no es un valor válido para un uint no más que 0,5 es, por lo que su ejemplo wouldn compilar

Ahora, en cuanto al resto: los tipos de enteros simplemente envuelven el desbordamiento, al igual que agregar 1 a int.MaxValue devuelve int.MinValue. Esta es una mejora significativa en el rendimiento en comparación con el hecho de que el programa verifique el desbordamiento de cada operación, a costa de no detectar un error.

Eso es solo si se encuentra en un contexto sin marcar, pero si realiza alguna de estas operaciones en un contexto verificado, obtendrá una excepción. Por ejemplo;

class Test 
{ 
    static void Main() 
    { 
     checked 
     { 
      uint a = 5; 
      uint b = 6; 
      uint c = a - b; 
     } 
    } 
} 

Run eso y verá un OverflowException son lanzados. Si eso es lo que quiere para su proyecto completo, puede configurarlo en las propiedades del proyecto (o compilar con la opción de línea de comando /checked+ en csc.)

EDITAR: Vale la pena señalar que las otras respuestas han demostrado que podría poner cantidades más pequeñas de código en el contexto verificado: solo la declaración y asignación de c o incluso solo el cálculo. Todo es bastante flexible.

+0

Darm - pegado a ella ... Presiono "Publicar" para encontrar que ya tiene +5 ... [eliminar ...] –

+0

Ese es un conjunto de votos terriblemente rápido. No es como si hubiera estado sentado por un tiempo ... –

+1

Sorprendentemente, nunca me he encontrado con los contextos marcados y sin marcar. Esto es genial. – Llyle

7

El ajuste se debe a que por defecto C# está desmarcado. Si se agrega un bloque "marcado", se detectará el desbordamiento:

uint a = 3, b = 4; 
    checked 
    { 
     uint c = a - b; // throws an overflow 
    } 

Como para el compilador, sino que sólo exige datos válidos.

+0

Estoy acostumbrado a un entorno comprobado, por lo que miré en MSDN, y esto indica que marcado es el predeterminado? - http://msdn.microsoft.com/en-us/library/74b4xzyw(VS.85).aspx – MattH

3

Esto es solo lo predeterminado: puede cambiar la configuración de compilación para habilitar las comprobaciones de desbordamiento aritéticas en tiempo de ejecución. Si enciende eso, se lanzarán excepciones como espera. Alternativamente, puede activar la comprobación de una operación específica colocándola dentro de un bloque marcado.

uint c = checked(a - b); 
0

Probablemente Cabe aclarar aquí que uint es un entero sin signo , no un sin asignar int. ¡Gran diferencia!

-2

La razón por la que se envuelve en negativo es debido a la matemática Two's Complement que se utiliza para la aritmética de enteros.

La respuesta corta es que el bit más significativo se utiliza como el signo. Un cero es positivo; uno es negativo

+0

uint = unsigned int – eplawless

-1

Siempre use doble.La diferencia de rendimiento es insignificante, y es más flexible y complaciente. Esta práctica evita excepciones y reduce el tiempo de desarrollo. La gente anal lo odia sin embargo.