¿Cuáles son las mejores prácticas con respecto a las entradas sin firma?

38

Uso ints sin firmar en todas partes, y no estoy seguro de si debería. Esto puede ser desde columnas de ID de clave primaria de la base de datos hasta contadores, etc. Si un número nunca debe ser negativo, entonces siempre usaré un int sin signo.

Sin embargo, observo en el código de otros que nadie más parece hacer esto. ¿Hay algo crucial que estoy pasando por alto?

Editar: Desde esta pregunta también he notado que en C, devolver valores negativos para errores es algo común en lugar de lanzar excepciones como en C ++.

    
pregunta wting 01.08.2011 - 12:17

11 respuestas

27
  

¿Hay algo crucial que estoy pasando por alto?

Cuando los cálculos incluyen tanto tipos firmados y sin firmar como diferentes tamaños, las reglas para la promoción de tipos pueden ser complejas y llevar a comportamiento inesperado .

Creo que esta es la razón principal por la que Java omite los tipos int sin firmar.

    
respondido por el Michael Borgwardt 01.08.2011 - 13:02
17

Creo que Michael tiene un punto válido, pero OMI, la razón por la que todo el mundo usa int todo el tiempo (especialmente en for (int i = 0; i < max, i++ ) es que lo aprendimos de esa manera. Cuando cada ejemplo en un libro ' cómo aprender a programar ' usa int en un bucle for , muy pocos cuestionarán esa práctica.

La otra razón es que int es 25% más corto que uint , y todos somos perezosos ... ;-)

    
respondido por el Treb 01.08.2011 - 13:50
10

La codificación de la información del rango en tipos es Una cosa buena. Se aplica el uso de números razonables en tiempo de compilación.

Muchas arquitecturas parecen tener instrucciones especializadas para tratar con int - > float conversiones. La conversión de unsigned puede ser más lenta (un poco) .

    
respondido por el Benjamin Bannier 01.08.2011 - 12:44
8

La mezcla de tipos firmados y no firmados puede llevarlo a un mundo de dolor. Y no puede usar todos los tipos sin firma porque encontrará cosas que tienen un rango válido que incluye números negativos o necesitan un valor para indicar un error y -1 es lo más natural. Entonces, el resultado neto es que muchos programadores usan todos los tipos de enteros con signo.

    
respondido por el David Schwartz 13.08.2011 - 16:20
6

Para mí, los tipos tienen mucho que ver con la comunicación. Al usar explícitamente un int sin signo, usted me dice que los valores firmados no son valores válidos. Esto me permite agregar algo de información al leer su código además del nombre de la variable. Lo ideal sería que un tipo no anónimo me dijera más, pero me da más información que si hubiera usado ints en todas partes.

Lamentablemente, no todo el mundo está muy consciente de lo que se comunica con su código, y esa es probablemente la razón por la que se ve en todas partes, a pesar de que los valores al menos están sin firmar.

    
respondido por el daramarak 01.08.2011 - 14:03
5

Utilizo unsigned int en C ++ para los índices de matriz, en su mayoría, y para cualquier contador que comience desde 0. Creo que es bueno decir explícitamente que "esta variable no puede ser negativa".

    
respondido por el quant_dev 01.08.2011 - 12:52
3

Debería preocuparse por esto cuando se trata de un número entero que en realidad podría acercarse o exceder los límites de un int firmado. Dado que el máximo positivo de un entero de 32 bits es 2.147.483.647, entonces debe usar un int sin signo si sabe que a) nunca será negativo yb) podría alcanzar los 2.147.483.648. En la mayoría de los casos, incluidas las claves de la base de datos y los contadores, nunca me acercaré a este tipo de números, por lo que no me preocupa preocuparme por si el bit de signo se usa para un valor numérico o para indicar el signo.

Yo diría: use int a menos que sepa que necesita un int sin firmar.

    
respondido por el Joel Etherton 01.08.2011 - 12:25
3

Es una compensación entre simplicidad y confiabilidad. Cuantos más errores se puedan detectar en tiempo de compilación, más confiable será el software. Diferentes personas y organizaciones están en diferentes puntos a lo largo de ese espectro.

Si alguna vez realiza una programación de alta confiabilidad en Ada, incluso usa diferentes tipos para variables como la distancia en pies y la distancia en metros, y el compilador lo marca si se asigna uno a otro accidentalmente. Eso es perfecto para programar un misil guiado, pero exageración (juego de palabras intencional) si está validando un formulario web. No hay necesariamente nada malo en ambos sentidos, siempre y cuando cumpla con los requisitos.

    
respondido por el Karl Bielefeldt 01.08.2011 - 19:05
2

Me inclino a estar de acuerdo con el razonamiento de Joel Etherton, pero llegué a la conclusión opuesta. De la manera que lo veo, incluso si sabe que es poco probable que los números se acerquen a los límites de un tipo firmado, si sabe que los números negativos no ocurrirán, entonces hay muy pocas razones para usar la variante firmada de un tipo.

Por la misma razón por la que, en algunas instancias seleccionadas, he usado BIGINT (entero de 64 bits) en lugar de INTEGER (entero de 32 bits) en las tablas de SQL Server. La probabilidad de que los datos alcancen el límite de 32 bits dentro de un período de tiempo razonable es minúscula, pero si sucede, las consecuencias en algunas situaciones podrían ser bastante devastadoras. Solo asegúrese de asignar los tipos entre los idiomas correctamente, o de lo contrario va a terminar con interesantes rarezas en el camino ...

Dicho esto, para algunas cosas, como los valores de la clave principal de la base de datos, con o sin firma, realmente no importa, porque a menos que esté reparando manualmente datos rotos o algo por el estilo, nunca tratará el valor directamente ; Es un identificador, nada más. En esos casos, la consistencia es probablemente más importante que la elección exacta de firmeza. De lo contrario, terminará con algunas columnas de clave externa que están firmadas y otras que no están firmadas, sin un patrón aparente, o con esa rareza interesante nuevamente.

    
respondido por el a CVn 01.08.2011 - 16:35
1

Recomendaría que fuera de los contextos de almacenamiento de datos y de intercambio de datos con espacio limitado, generalmente se deberían usar tipos firmados. En la mayoría de los casos donde un entero con signo de 32 bits sería demasiado pequeño, pero un valor sin signo de 32 bits sería suficiente para hoy, no pasará mucho tiempo antes de que el valor sin signo de 32 bits tampoco sea lo suficientemente grande.

Los tiempos primarios en los que se deben usar tipos sin signo son cuando uno está ensamblando múltiples valores en uno más grande (por ejemplo, convirtiendo cuatro bytes en un número de 32 bits) o descomponiendo valores mayores en valores más pequeños (por ejemplo, almacenando un número de 32 bits como cuatro bytes), o cuando uno tiene una cantidad que se espera que se "transfiera" periódicamente y uno tiene que lidiar con eso (piense en un medidor de servicios públicos residenciales; la mayoría de ellos tiene suficientes dígitos para garantizar que no puedan rodar) entre lecturas si se leen tres veces al año, pero no lo suficiente como para garantizar que no se traspasen dentro de la vida útil del medidor). Los tipos no firmados a menudo tienen suficiente 'rareza' como para que solo se usen en los casos en que su semántica sea necesaria.

    
respondido por el supercat 13.07.2012 - 23:42
0

Uso ints sin firmar para que mi código y su intención sean más claros. Una cosa que hago para protegerme contra conversiones implícitas inesperadas al realizar operaciones aritméticas con tipos firmados y sin firmar es usar un corto sin signo (generalmente 2 bytes) para mis variables sin firmar. Esto es efectivo por un par de razones:

  • Cuando haces aritmética con tus variables cortas y literales sin firmar (que son del tipo int) o variables de tipo int, esto asegura que la variable sin signo siempre se promoverá a un int antes de evaluar la expresión, ya que int siempre tiene una mayor Rango que corto. Esto evita cualquier comportamiento inesperado haciendo aritmética con tipos firmados y sin firmar, asumiendo que el resultado de la expresión encaja en un int firmado, por supuesto.
  • La mayoría de las veces, las variables sin signo que está utilizando no superarán el valor máximo de un corto de 2 bytes sin signo (65,535)

El principio general es que el tipo de sus variables sin signo debe tener un rango más bajo que el tipo de las variables con signo para garantizar la promoción al tipo con signo. Entonces no tendrás ningún comportamiento de desbordamiento inesperado. Obviamente, no puedes asegurar esto todo el tiempo, pero (la mayoría) a menudo es posible asegurar esto.

Por ejemplo, recientemente tuve algo así como un bucle como este:

const unsigned short cuint = 5;
for(unsigned short i=0; i<10; ++i)
{
    if((i-2)%cuint == 0)
    {
       //Do something
    }
}

El literal '2' es de tipo int. Si yo fuera un int sin signo en lugar de un corto sin firmar, entonces, en la subexpresión (i-2), 2 se promocionaría a un int sin signo (ya que int sin signo tiene una prioridad más alta que int firmado). Si i = 0, entonces la subexpresión es igual a (0u-2u) = algún valor masivo debido al desbordamiento. La misma idea con i = 1. Sin embargo, dado que i es un corto sin firma, se promueve al mismo tipo que el literal '2', que está firmado como int, y todo funciona bien.

Para mayor seguridad: en el raro caso de que la arquitectura que está implementando en las causas int sea de 2 bytes, esto podría hacer que ambos operandos en la expresión aritmética se conviertan a int sin signo en el caso en que la variable corta sin signo no no encaja en el int firmado de 2 bytes, el último de los cuales tiene un valor máximo de 32,767 < 65.535. (Consulte enlace para obtener más detalles). Para protegerse contra esto, simplemente puede agregar un static_assert a su programa de la siguiente manera:

static_assert(sizeof(int) == 4, "int must be 4 bytes");

y no se compilará en arquitecturas donde int es de 2 bytes.

    
respondido por el AdmiralAdama 12.12.2018 - 14:34

Lea otras preguntas en las etiquetas

Comentarios Recientes

Por supuesto, sin mucha advertencia formal, agregar un puntero o llamar a malloc () en la matriz valarg siempre degrada las páginas del montón. Por defecto, los tipos de datos numéricos actualizables (NDN) usan un puntero para almacenar todo almacenado en una gran cantidad de grupos organizados de 32 bytes (rectángulos). Además, la mayoría de los punteros regresan y, por lo tanto, hacen referencia y envían el trabajo en pilas individuales. Por lo tanto, estos tipos no se pueden reasignar. Sin embargo, los mensajes... Lee mas