¿Cuándo usar valores sin firmar sobre los firmados?

81

¿Cuándo es apropiado usar una variable sin firmar sobre una firmada? ¿Y en un forbucle?

Escuché muchas opiniones sobre esto y quería ver si había algo parecido a un consenso.

for (unsigned int i = 0; i < someThing.length(); i++) {  
    SomeThing var = someThing.at(i);  
    // You get the idea.  
}

Sé que Java no tiene valores sin firmar, y esa debe haber sido una decisión consciente por parte de Sun Microsystems .

Bernardo
fuente
1
Encontré esto útil: codemines.blogspot.ca/2007/10/…
mk12
Creo que esta pregunta se basa bastante en opiniones. El código presentado se ejecutará bien en ambos casos, por lo que puede usar ambos. Excepto por razones de rendimiento (hasta ahora ninguna respuesta se refiere al rendimiento), es solo gusto personal.
Trilarion

Respuestas:

69

Me alegré de encontrar una buena conversación sobre este tema, ya que no lo había pensado mucho antes.

En resumen, con signo es una buena opción general, incluso cuando está completamente seguro de que todos los números son positivos, si va a hacer aritmética en la variable (como en un caso típico de bucle for).

Si va a hacer cosas bit a bit como máscaras, sin firmar comienza a tener más sentido. O, si está desesperado por obtener ese rango positivo adicional aprovechando el bit de signo.

Personalmente, me gusta firmar porque no confío en mí mismo para mantener la coherencia y evitar mezclar los dos tipos (como advierte el artículo).

saint_groceon
fuente
3
Más adelante en ese hilo, se muestra que unsignedes muy superior para detectar desbordamientos en entradas que no son de confianza. Desafortunadamente, las "respuestas" propuestas al rompecabezas no son tan buenas. La mía es que template<size_t limit> bool range_check_sum( unsigned a, unsigned b ) { return (a < limit) && (b < limit - a); } si alguien tiene una respuesta igualmente simple y directa usando tipos firmados, me encantaría verla.
Ben Voigt
10

En su ejemplo anterior, cuando 'i' siempre será positivo y un rango más alto sería beneficioso, sin firmar sería útil. Como si estuviera usando declaraciones 'declarar', como:

#declare BIT1 (unsigned int 1)
#declare BIT32 (unsigned int reallybignumber)

Especialmente cuando estos valores nunca cambiarán.

Sin embargo, si está realizando un programa de contabilidad en el que las personas son irresponsables con su dinero y están constantemente en números rojos, definitivamente querrá usar 'firmado'.

Sin embargo, estoy de acuerdo con saint en que una buena regla general es usar firmado, que C en realidad es el predeterminado, por lo que está cubierto.

holaandre
fuente
9

Creo que si su caso de negocios dicta que un número negativo no es válido, le gustaría que se mostrara o arrojara un error.

Con eso en mente, recientemente descubrí los números enteros sin firmar mientras trabajaba en un proyecto que procesaba datos en un archivo binario y los almacenaba en una base de datos. A propósito, estaba "corrompiendo" los datos binarios y terminé obteniendo valores negativos en lugar de un error esperado. Descubrí que aunque el valor se convirtió, el valor no era válido para mi caso comercial.
Mi programa no falló y terminé obteniendo datos incorrectos en la base de datos. Hubiera sido mejor si lo hubiera usado uinty hubiera fallado el programa.

Keith Sirmons
fuente
8

Los compiladores de C y C ++ generarán una advertencia cuando compare tipos firmados y no firmados; en su código de ejemplo, no podría hacer que su variable de bucle no esté firmada y que el compilador genere código sin advertencias (suponiendo que dichas advertencias estén activadas).

Naturalmente, está compilando con advertencias al máximo, ¿verdad?

Y, ¿ha considerado compilar con "tratar las advertencias como errores" para ir un paso más allá?

La desventaja de usar números con signo es que existe la tentación de sobrecargarlos para que, por ejemplo, los valores 0-> n sean la selección del menú, y -1 significa que no hay nada seleccionado, en lugar de crear una clase que tenga dos variables, una para indicar si algo está seleccionado y otro para almacenar cuál es esa selección. Antes de que te des cuenta, estás probando uno negativo por todas partes y el compilador se queja de cómo quieres comparar la selección del menú con la cantidad de selecciones de menú que tienes, pero eso es peligroso porque son de diferentes tipos. . Así que no hagas eso.

Josh
fuente
6

size_ta menudo es una buena opción para esto, o size_typesi está utilizando una clase STL.

Mark Harrison
fuente
Solo cuando se trata del tamaño de algo en bytes.
mk12
Los contenedores de la biblioteca estándar @ mk12 exponen al size_typemiembro para recuentos de elementos, no solo bytes. Debería usarse en lugar de std::size_tdonde esté disponible, pero es inexacto dar a entender que cualquier cosa que comience con size_tsolo puede significar bytes.
underscore_d