-2147483648 es el número entero más pequeño para el tipo entero con 32 bits, pero parece que se desbordará en la if(...)
oración:
if (-2147483648 > 0)
std::cout << "true";
else
std::cout << "false";
Esto se imprimirá true
en mis pruebas. Sin embargo, si lanzamos -2147483648 a entero, el resultado será diferente:
if (int(-2147483648) > 0)
std::cout << "true";
else
std::cout << "false";
Esto se imprimirá false
.
Estoy confundido. ¿Alguien puede dar una explicación sobre esto?
Actualización 02-05-2012:
Gracias por sus comentarios, en mi compilador, el tamaño de int es de 4 bytes. Estoy usando VC para algunas pruebas simples. He cambiado la descripción en mi pregunta.
Esas son muchas respuestas muy buenas en esta publicación, AndreyT dio una explicación muy detallada sobre cómo el compilador se comportará en dicha entrada y cómo se implementó este entero mínimo. qPCR4vir por otro lado dio algunas "curiosidades" relacionadas y cómo se representan los enteros. ¡Tan impresionante!
fuente
INT_MIN
de-9223372036854775808
, siCHAR_BIT
es 16. E incluso conCHAR_BIT == 8
ysizeof(int
== 4) `puede obtener-9223372036854775807
porque C no requiere números de 2 Complementos.Respuestas:
-2147483648
No es un "número". El lenguaje C ++ no admite valores literales negativos.-2147483648
es en realidad una expresión: un valor literal positivo2147483648
con-
operador unario en frente. El valor2147483648
es aparentemente demasiado grande para el lado positivo delint
rango en su plataforma. Si el tipolong int
tuviera un rango mayor en su plataforma, el compilador tendría que asumir automáticamente que2147483648
tienelong int
tipo. (En C ++ 11, el compilador también tendría que considerar ellong long int
tipo). Esto haría que el compilador evaluara-2147483648
en el dominio de tipo más grande y el resultado sería negativo, como cabría esperar.Sin embargo, aparentemente en su caso el rango de
long int
es el mismo que el rango deint
, y en general no hay un tipo entero con un rango mayor queint
en su plataforma. Esto significa formalmente que la constante positiva2147483648
desborda todos los tipos de enteros con signo disponibles, lo que a su vez significa que el comportamiento de su programa no está definido. (Es un poco extraño que la especificación del lenguaje opte por un comportamiento indefinido en tales casos, en lugar de requerir un mensaje de diagnóstico, pero así es como es).En la práctica, teniendo en cuenta que el comportamiento es indefinido,
2147483648
puede interpretarse como un valor negativo dependiente de la implementación que se vuelve positivo después de haberse-
aplicado unario . Alternativamente, algunas implementaciones podrían decidir intentar usar tipos sin signo para representar el valor (por ejemplo, en C89 / 90 se requería usar compiladoresunsigned long int
, pero no en C99 o C ++). Las implementaciones pueden hacer cualquier cosa, ya que el comportamiento no está definido de todos modos.Como nota al margen, esta es la razón por la cual las constantes como
INT_MIN
se suelen definir comoen lugar del aparentemente más directo
Este último no funcionaría según lo previsto.
fuente
#define INT_MIN (-2147483647 - 1)
.int
. La implementación de OP puede no tener un tipo de 64 bits.-1.0
se analice como un valor doble negativo, ¿no?unsigned long int
en este contexto, pero en C99 este permiso fue eliminado. Se requieren literales sin sufijo en C y C ++ para tener tipos firmados . Si ve un tipo sin firmar aquí cuando uno con signo funcionaría, significa que su compilador está dañado. Si ve un tipo sin signo aquí cuando ningún tipo con signo funcionaría, entonces esto es solo una manifestación específica de comportamiento indefinido.El compilador (VC2012) promueve los enteros "mínimos" que pueden contener los valores. En el primer caso,
signed int
(ylong int
) no puede (antes de que se aplique el signo), perounsigned int
puede: ¿2147483648
tieneunsigned int
???? tipo. En el segundo forzasint
desde elunsigned
.Aquí hay "curiosidades" relacionadas:
C ++ 11 estándar :
...
...
Y estas son las reglas de promociones para enteros en el estándar.
fuente
int
,long int
,unsigned long int
para representar las constantes decimales unsuffixed. Ese fue el único lenguaje que permitió el uso de tipos sin signo para constantes decimales sin mezclar. En C ++ 98 eraint
olong int
. No se permiten tipos sin firmar. Ni C (a partir de C99) ni C ++ permiten que el compilador use tipos sin signo en este contexto. Su compilador es, por supuesto, libre de usar tipos sin signo si ninguno de los firmados funciona, pero esto sigue siendo solo una manifestación específica de comportamiento indefinido.int
olong int
representar2147483648
. Además, que yo sepa, en tanto VC2012int
ylong int
son tipos de 32 bits. Esto significa que en VC2012 literal2147483648
debería conducir a un comportamiento indefinido . Cuando el comportamiento no está definido, el compilador puede hacer cualquier cosa. Eso significaría que VC2012 no está roto. Simplemente emitió un mensaje de diagnóstico engañoso. En lugar de decirle que el comportamiento es completamente indefinido, decidió usar un tipo sin signo.long
y no está obligado a emitir un diagnóstico? Eso parecería roto.En resumen, se
2147483648
desborda-2147483648
y(-(-2147483648) > 0)
estrue
.Así es como se
2147483648
ve en binario.Además, en el caso de los cálculos binarios con signo, el bit más significativo ("MSB") es el bit de signo. Esta pregunta puede ayudar a explicar por qué.
fuente
Debido a
-2147483648
que en realidad se aplica2147483648
con negación (-
), el número no es lo que esperarías. En realidad es el equivalente de este pseudocódigo:operator -(2147483648)
Ahora, suponiendo que su compilador sea
sizeof(int)
igual4
yCHAR_BIT
se defina como8
, eso haría que el2147483648
desbordamiento sea el valor máximo con signo de un entero (2147483647
). Entonces, ¿cuál es el máximo más uno? Vamos a resolver eso con un entero de 4 bits y 2 segundos.¡Espere! 8 desborda el entero! qué hacemos? Utilice su representación sin signo
1000
e interprete los bits como un entero con signo. Esta representación nos deja con la-8
aplicación de la negación del complemento 2 que resulta en8
, que, como todos sabemos, es mayor que0
.Esta es la razón por la cual
<limits.h>
(y<climits>
) comúnmente se defineINT_MIN
como((-2147483647) - 1)
- para que el entero con signo máximo (0x7FFFFFFF
) se niegue (0x80000001
), luego se disminuya (0x80000000
).fuente
-8
sigue siendo-8
.-(8)
qué en C ++ es lo mismo que-8
: es la negación aplicada a un literal, no a un literal negativo. El literal es8
, que no cabe en un entero de 4 bits con signo, por lo que debe estar sin signo. El patrón es1000
. Hasta ahora tu respuesta es correcta. La negación del complemento de dos1000
en 4 bits es1000
que no importa si está firmado o no. Su respuesta dice "interprete los bits como un entero con signo", lo que hace que el valor-8
después de la negación del complemento a los dos, tal como era antes de la negación.8
. Se aplica la negación (módulo 16), dando como resultado una respuesta final de8
. La codificación sigue siendo 1000 pero el valor es diferente porque se eligió un tipo sin signo.