Nuestros mejores programadores han agotado sus reservas de café, en su búsqueda todo el tiempo por la solución, hasta que Gustavo encontró la contestación en Bitbucket y hoy la compartimos contigo.
Solución:
-2147483648
no es un “número”. El lenguaje C++ no admite valores literales negativos.
-2147483648
es en realidad una expresión: un valor literal positivo 2147483648
con unario -
operador frente a él. Valor 2147483648
es aparentemente demasiado grande para el lado positivo de int
gama en su plataforma. Si escribe long int
tuviera un mayor rango en su plataforma, el compilador tendría que asumir automáticamente que 2147483648
posee long int
tipo. (En C++11 el compilador también tendría que considerar long long int
type.) Esto haría que el compilador evalúe -2147483648
en el dominio de tipo más grande y el resultado sería negativo, como era de esperar.
Sin embargo, aparentemente en su caso el rango de long int
es el mismo que el rango de int
y en general no hay ningún tipo entero con mayor rango que int
en tu plataforma. Esto significa formalmente que la constante positiva 2147483648
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 idioma opte por un comportamiento indefinido en tales casos, en lugar de requerir un mensaje de diagnóstico, pero así son las cosas).
En la práctica, teniendo en cuenta que el comportamiento es indefinido, 2147483648
podría interpretarse como un valor negativo dependiente de la implementación que se vuelve positivo después de tener unario -
aplicado a ella. Alternativamente, algunas implementaciones podrían decidir intentar usar tipos sin firmar para representar el valor (por ejemplo, en C89/90 los compiladores debían usar unsigned 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 constantes como INT_MIN
normalmente se definen como
#define INT_MIN (-2147483647 - 1)
en lugar de lo aparentemente más sencillo
#define INT_MIN -2147483648
Este último no funcionaría según lo previsto.
El compilador (VC2012) promociona a los enteros “mínimos” que pueden contener los valores. En el primer caso, signed int
(y long int
) no puede (antes de que se aplique el signo), pero unsigned int
puede: 2147483648
posee unsigned int
???? tipo. En el segundo obligas int
desde el unsigned
.
const bool i= (-2147483648 > 0) ; // --> true
advertencia C4146: operador menos unario aplicado a tipo sin firmarresultado todavía no firmado
Aquí hay “curiosidades” relacionadas:
const bool b= (-2147483647 > 0) ; // false
const bool i= (-2147483648 > 0) ; // true : result still unsigned
const bool c= ( INT_MIN-1 > 0) ; // true :'-' int constant overflow
const bool f= ( 2147483647 > 0) ; // true
const bool g= ( 2147483648 > 0) ; // true
const bool d= ( INT_MAX+1 > 0) ; // false:'+' int constant overflow
const bool j= ( int(-2147483648)> 0) ; // false :
const bool h= ( int(2147483648) > 0) ; // false
const bool m= (-2147483648L > 0) ; // true
const bool o= (-2147483648LL > 0) ; // false
Estándar C++11:
2.14.2 Literales enteros [lex.icon]
…
Un literal entero es una secuencia de dígitos que no tiene punto ni exponente. Un literal entero puede tener un prefix que especifica su base y un sufijo que especifica su tipo.
…
El tipo de un literal entero es el primero de la lista correspondiente en la que se puede representar su valor.
Si un literal entero no puede ser representado por ningún tipo en su lista y un tipo entero extendido (3.9.1) puede representar su valor, puede tener ese tipo entero extendido. Si todos los tipos de la lista del literal están firmados, se firmará el tipo entero extendido. Si todos los tipos de la lista del literal no tienen signo, el tipo entero extendido no tendrá signo. Si la lista contiene tipos con y sin signo, el tipo entero extendido puede ser con o sin signo. Un programa está mal formado si una de sus unidades de traducción contiene un literal entero que no puede ser representado por ninguno de los tipos permitidos.
Y estas son las reglas de promoción para números enteros en el estándar.
4.5 Promociones Integrales [conv.prom]
Un valor pr de un tipo entero distinto de
bool
,char16_t
,char32_t
o
wchar_t
cuyo rango de conversión de enteros (4.13) es menor que el rango de int se puede convertir a un prvalue de tipoint
Siint
puede representar todos los valores del tipo fuente; de lo contrario, el prvalue de origen se puede convertir en un prvalue de tipounsigned int
.
En breve, 2147483648
se desborda a -2147483648
y (-(-2147483648) > 0)
es true
.
Así es como 2147483648
parece en binario.
Además, en el caso de cálculos binarios con signo, el bit más significativo (“MSB”) es el bit de signo. Esta pregunta puede ayudar a explicar por qué.
Puedes asentar nuestra faena mostrando un comentario y valorándolo te damos las gracias.