c++ - Comparaciones firmadas/sin firmar
visual-studio-2005 comparison (4)
Al comparar firmado con unsigned, el compilador convierte el valor firmado a unsigned. Para la igualdad, esto no importa, -1 == (unsigned) -1
. Para otras comparaciones, importa, por ejemplo, lo siguiente es cierto: -1 > 2U
.
EDITAR: Referencias:
5/9: (Expresiones)
Muchos operadores binarios que esperan operandos de tipo aritmético o de enumeración causan conversiones y producen tipos de resultados de forma similar. El propósito es producir un tipo común, que también es el tipo del resultado. Este patrón se denomina conversiones aritméticas habituales, que se definen de la siguiente manera:
Si cualquiera de los dos operandos es del tipo double long, el otro se convertirá a double double.
De lo contrario, si cualquiera de los dos operandos es doble, el otro se convertirá en doble.
De lo contrario, si alguno de los operandos es flotante, el otro se convertirá en flotante.
De lo contrario, las promociones integrales (4.5) se realizarán en ambos operandos.54)
Entonces, si cualquiera de los operandos tiene un largo sin signo, el otro se convertirá a largo sin signo.
De lo contrario, si un operando es un int largo y el otro unsigned int, entonces si un int largo puede representar todos los valores de un int sin firmar, el int sin firmar se convertirá en un int largo; de lo contrario, ambos operandos se convertirán a unsigned long int.
De lo contrario, si alguno de los operandos es largo, el otro se convertirá en largo.
De lo contrario, si ninguno de los operandos está sin firmar, el otro se convertirá en unsigned.
4.7 / 2: (Conversiones integrales)
Si el tipo de destino no está firmado, el valor resultante es el entero menos sin signo congruente con el entero de origen (módulo 2 n donde n es el número de bits utilizados para representar el tipo sin signo). [Nota: en una representación de complemento de dos, esta conversión es conceptual y no hay cambios en el patrón de bits (si no hay truncamiento). ]
EDIT2: niveles de advertencia de MSVC
Lo que se advierte sobre los diferentes niveles de advertencia de MSVC es, por supuesto, las elecciones hechas por los desarrolladores. Como lo veo, sus elecciones en relación con la igualdad firmada / no firmada frente a las comparaciones mayor / menor tienen sentido, esto es completamente subjetivo, por supuesto:
-1 == -1
significa lo mismo que -1 == (unsigned) -1
- Encuentro ese resultado intuitivo.
-1 < 2
no significa lo mismo que -1 < (unsigned) 2
- Esto es menos intuitivo a primera vista, y la OMI merece una advertencia "anterior".
Estoy tratando de entender por qué el siguiente código no emite una advertencia en el lugar indicado.
//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX 2147483647 /* maximum (signed) int value */
/* = 0x7fffffff */
int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;
if(a < b) // warning C4018: ''<'' : signed/unsigned mismatch
c = true;
if(a > b) // warning C4018: ''<'' : signed/unsigned mismatch
c = true;
if(a <= b) // warning C4018: ''<'' : signed/unsigned mismatch
c = true;
if(a >= b) // warning C4018: ''<'' : signed/unsigned mismatch
c = true;
if(a == b) // no warning <--- warning expected here
c = true;
if(((unsigned int)a) == b) // no warning (as expected)
c = true;
if(a == ((int)b)) // no warning (as expected)
c = true;
Pensé que tenía que ver con la promoción de fondo, pero los dos últimos parecen decir lo contrario.
En mi opinión, ¿la primera comparación ==
es tanto un desajuste firmado / no firmado como los demás?
El operador == simplemente hace una comparación bit a bit (por división simple para ver si es 0).
Las comparaciones más pequeñas / más grandes dependen mucho más del signo del número.
Ejemplo de 4 bits:
1111 = 15? o -1?
entonces si tienes 1111 <0001 ... es ambiguo ...
pero si tienes 1111 == 1111 ... Es lo mismo aunque no quisiste decirlo.
En un sistema que representa los valores usando el complemento 2 (la mayoría de los procesadores modernos) son iguales incluso en su forma binaria. Esta puede ser la razón por la cual el compilador no se queja de a == b .
Y para mí es extraño que el compilador no lo advierta en a == ((int) b) . Creo que debería darle una advertencia de truncamiento entero o algo así.
Por qué las advertencias firmadas / no firmadas son importantes y los programadores deben prestarles atención, se demuestra en el siguiente ejemplo.
Adivina el resultado de este código?
#include <iostream>
int main() {
int i = -1;
unsigned int j = 1;
if ( i < j )
std::cout << " i is less than j";
else
std::cout << " i is greater than j";
return 0;
}
Salida:
i is greater than j
¿Sorprendido? Demostración en línea: http://www.ideone.com/5iCxY
En pocas palabras: en comparación, si un operando unsigned
está unsigned
, entonces el otro operando se convierte implícitamente en unsigned
si su tipo está firmado.