2010-06-22 19 views
75

He observado por un tiempo que los programadores de C# tienden a usar int en todas partes, y rara vez recurren a uint. Pero nunca descubrí una respuesta satisfactoria sobre por qué.usando uint vs int

Si la interoperabilidad es su objetivo, uint no debería aparecer en las API públicas porque no todos los lenguajes CLI admiten enteros sin signo. Pero eso no explica por qué int es tan frecuente, incluso en las clases internas. Sospecho que esta es la razón por la cual uint se usa con moderación en el BCL.

En C++, si tiene un número entero para el que los valores negativos no tienen sentido, debe elegir un entero sin signo.

Esto claramente significa que los números negativos no son permitidos o esperados, y el compilador hará una cierta verificación por usted. También sospecho que en el caso de los índices de matriz, el JIT puede soltar fácilmente la verificación de límites inferiores.

Sin embargo, al mezclar int y tipos de unidades, se necesitarán cuidados adicionales y moldes.

¿Debería usarse más? ¿Por qué?

+0

http://stackoverflow.com/questions/6301/why-is-array-length-an-int-and-not-an-uint – drharris

+0

Sólo heught Tuve un deja vu: D, casi exactamente la misma pregunta se ha preguntado hace poco tiempo. – KroaX

+0

En cuanto a las comprobaciones de límites inferiores (en caso de que necesite escribir las suyas), puede reemplazar 'if (i < 0 || i > = length)' con 'if (unchecked ((uint) i)> length)'. IL resultante tendrá una instrucción (rama) menos en total y dará aproximadamente el mismo rendimiento (infinitesimalmente más rápido). Personalmente, me encanta porque me rasca la comezón de comprobar los límites inferiores. Es probable que otros argumenten en contra de ella debido a que "no se controla", pero yo sostengo que esta es una muy buena línea para aprender su significado porque es simple e instantáneamente claro desde el contexto cuál es el propósito = ayuda al lector a aprender. – AnorZaken

Respuesta

47

Su observación de por qué uint no se utiliza en el BCL es la razón principal, sospecho.

UInt32 no cumple con CLS, lo que significa que es totalmente inapropiado para su uso en API públicas. Si va a utilizar uint en su API privada, esto significará realizar conversiones a otros tipos, y generalmente es más fácil y seguro mantener el mismo tipo.

También sospecho que esto no es tan común en el desarrollo de C#, incluso cuando C# es el único idioma utilizado, principalmente porque no es común en el BCL. Los desarrolladores, en general, intentan (afortunadamente) imitar el estilo del marco en el que están construyendo: en el caso de C#, esto significa tratar de hacer que sus API, públicas e internas, se parezcan tanto a .NET Framework BCL como sea posible. Esto significaría usar uint con moderación.

+0

http://stackoverflow.com/questions/2013116/should-i-use-uint-in-c-for-values-that-cant-be-negative es una pregunta que trata de un tema similar – Stephan

71

int es más corto para escribir que uint.

+2

Sospecho que esto es bastante cercano a la verdad. ¿Por qué usar 'uint' cuando el 99% de las veces (en mi experiencia)' int' será suficiente? –

+0

Sí, nunca tuve una razón para usar un 'uint'. Y, si necesito almacenar un número más grande, simplemente uso un 'largo'. Es bueno poder usar -1 como error o valor predeterminado. – jjnguy

+12

@Justin: "Números mágicos" como -1 no son una buena idea, en general. Cambiar a "largo" significa usar memoria 2x sin ninguna razón, así ... "unidad" definitivamente es valiosa, siempre que no necesites interactuar con otras API. –

4

Prefiero uint a int a menos que un número negativo esté realmente en el rango de valores aceptables. En particular, aceptar un parámetro int pero lanzar un ArgumentException si el número es menor que cero es simplemente una tontería: ¡use un uint!

Estoy de acuerdo en que uint está infrautilizado, y animo a todos los demás a usarlo más.

+7

Es muy peligroso para aceptar solo uints y no verificar los límites. Si alguien pasa un valor negativo, el CLR lo interpretará como un int grande, lo que significa que para -1 obtienes uint.maxvalue. Este no es un comportamiento deseado. – Henri

+18

@Henri: C# no tiene una conversión implícita de int a uint, por lo que no hay "Si alguien pasa un valor negativo". Por supuesto, una verificación de límites en el límite superior sigue siendo adecuada (pero ahora solo necesita una verificación en lugar de dos). –

0

Creo que es la pereza. C# es intrínsecamente una opción para el desarrollo en computadoras de escritorio y otras máquinas con relativamente muchos recursos.

C y C++, sin embargo, tiene profundas raíces en sistemas antiguos y sistemas integrados donde la memoria es escasa, por lo que los programadores se utilizan para pensar cuidadosamente qué tipo de datos usar. Los programadores de C# son flojos, y dado que hay suficientes recursos en general, nadie realmente optimiza el uso de la memoria (en general, no siempre por supuesto). Si un byte fuera suficiente, muchos programadores de C#, incluyéndome a mí, simplemente usan int para simplificar. Además, muchas funciones API aceptan entradas, por lo que previene el lanzamiento.

Acepto que elegir el tipo de datos correcto es una buena práctica, pero creo que la principal motivación es la pereza.

Por último, elegir un número entero es más matemáticamente correcto.Las entradas sin firmar no existen en matemáticas (solo números naturales). Y dado que la mayoría de los programadores tienen una formación matemática, usar un número entero es más natural.

+0

No diría que es pereza, aunque la pereza tiene sus méritos. Es más que la mayoría de las veces, simplemente no me importa lo más mínimo, desperdiciar mis ciclos cerebrales en una decisión así, y simplemente seguir con el int. El hardware es barato, los programadores pueden ser caros. – SWeko

+0

Los programadores son flojos. Eso es algo malo ¡Raymond diría que los programadores odian pagar sus impuestos! – Wizard79

+0

Sería el primero en administrar que los programadores de C# somos perezosos, pero eso no es necesariamente algo malo. – ChaosPandion

12

1) Mal hábito. Seriamente. Incluso en C/C++.

Piense en el patrón común for:

for(int i=0; i<3; i++) 
    foo(i); 

no hay absolutamente ninguna razón para utilizar un número entero allí. Nunca tendrás valores negativos. Pero casi todos harán un bucle simple de esa manera, incluso si contiene (al menos) otros dos errores de "estilo".

2) int se percibe como el tipo nativo de la máquina.

0

Creo que una gran parte del motivo es que cuando C apareció por primera vez, la mayoría de los ejemplos usaban int en aras de la brevedad. Nos regocijamos por no tener que escribir integer como hicimos con Fortran y Pascal, y en esos días los usábamos rutinariamente para cosas mundanas como índices de matriz y contadores de bucle. Los enteros sin signo eran casos especiales para números grandes que necesitaban ese último bit adicional. Creo que es una progresión natural que los hábitos C continúen en C# y otros nuevos lenguajes como Python.

1

Programo en una capa de aplicación de nivel más bajo donde los ints rara vez superan los 100, por lo que los valores negativos no son un problema (por ejemplo, para i < myname.length() cosas) es solo un viejo hábito de C, y más corto para escribir como se ha mencionado más arriba. Sin embargo, en algunos casos, cuando se hace interfaz con hardware en el que estoy tratando con indicadores de eventos de dispositivos, la uint es importante en los casos en que un indicador puede usar el bit más a la izquierda (el más alto).

Honestamente, para el 99.9% de mi trabajo podría usar usualmente el estilo corto, pero int, ya sabes, suena mucho mejor que ushort.

1

He hecho una envoltura Direct3D 10 en C# & necesito usar uint si quiero crear buffers de vértices muy grandes. Los búferes grandes en la tarjeta de video no se pueden representar con un int firmado.

UINT es muy útil & es tonto decir lo contrario. Si alguien piensa simplemente porque nunca han necesitado usar uint nadie más lo hará, estás equivocado.

+0

Es un buen caso en el que puede aprovechar el amplio rango. –

16

Normalmente int será suficiente. Si usted puede satisfacer todas las siguientes condiciones, puede utilizar uint:

  • No es una API pública (ya que no es compatible con uint CLS).
  • No necesita números negativos.
  • Usted (podría) necesitar el rango adicional.
  • Usted es no usándolo en comparación con < 0, ya que nunca es true.
  • Usted es no usándolo en comparación con >= 0, ya que nunca es false.

El último requisito es a menudo olvidado e introducirá errores:

static void Main(string[] args) 
{ 
    if (args.Length == 0) return; 
    uint last = (uint)(args.Length - 1); 

    // This will eventually throw an IndexOutOfRangeException: 
    for (uint i = last; i >= 0; i--) 
    { 
     Console.WriteLine(args[i]); 
    } 
} 
0

Algunos idiomas (por ejemplo,muchas versiones de Pascal) consideran que los tipos sin signo representan cantidades numéricas; una operación entre un tipo sin signo y un tipo firmado del mismo tamaño generalmente se realizará como si los operandos se promocionaran al siguiente tipo más grande (en algunos idiomas, el tipo más grande no tiene equivalente sin signo, por lo que tal promoción siempre será posible))

Otros idiomas (por ejemplo, C) consideran los tipos sin signo de N bits como un grupo que se ajusta al módulo 2^N. Tenga en cuenta que restar N de un miembro de dicho grupo no representa la resta numérica, sino que cede el miembro del grupo que, cuando se agrega N, arrojaría el original. Podría decirse que ciertas operaciones que involucran mezclas de valores firmados y no firmados realmente no tienen sentido y quizás deberían haber sido prohibidas, pero incluso el código que es descuidado con sus especificaciones de cosas como literales numéricos generalmente funcionará, y se ha escrito un código que mezcla firmado y tipos sin firmar y, a pesar de ser descuidado, funciona, que la especificación no es apta para cambiar pronto.

Es mucho más fácil trabajar exclusivamente con tipos firmados que resolver todas las complejidades de las interacciones entre los tipos firmados y no firmados. Los tipos sin signo son útiles al descomponer números grandes de piezas más pequeñas (por ejemplo, para serialización) o para reconfigurar tales números, pero en general es mejor simplemente usar números con signo para cosas que realmente representan cantidades

0

Sé que esto es probablemente un antiguo hilo, pero quería dar algunas aclaraciones.

Permite tomar un int8, puede almacenar -128 a 127 y usa 1 byte, que es un total de 127 números positivos.
Cuando usa un int8 uno de los bits se usa para los números negativos -128.
Cuando usa un Uint8, da los números negativos al positivo, por lo que le permite usar 255 números positivos con la misma cantidad de almacenamiento de 1 byte.
El único inconveniente es que ahora ha perdido la capacidad de usar valores negativos.
Otro problema con esto no son todos los lenguajes de programación y las bases de datos lo soportan.
La única razón por la que usaría esto en mi opinión es cuando necesita ser eficiente en la programación de juegos y tiene que almacenar números grandes no negativos. Es por eso que no muchos programas lo usan.

La razón principal es que el almacenamiento no es un problema y no puede usarlo de manera flexible con otro software, complementos, base de datos o Api. También, por ejemplo, un banco necesitaría números negativos para almacenar dinero, etc.

Espero que esto ayude a alguien.