-2147483648
, por ejemplo, no es un literal entero; es una expresión que consiste en un operador único -
aplicado al literal 2147483648
.
Antes del nuevo estándar C++ 2011, C++ no requiere la existencia de ningún tipo más grande que 32 bits (C++ 2011 agrega long long
), por lo que el literal 2147483648
no es portátil.
un entero decimal literal es del primero de los siguientes tipos en el que su valor adapta a:
int
long int
long long int (new in C++ 2011)
Nota que nunca es de un tipo sin signo en la norma C++. En las versiones de 1998 y 2003 del estándar C (que no tienen long long int
), un literal entero decimal que es demasiado grande para caber en long int
da como resultado un comportamiento indefinido. En C++ 2011, si un literal entero decimal no cabe en long long int
, entonces el programa está "mal formado".
Pero gcc (al menos a partir del release 4.6.1, el último que tengo) no implementa la semántica de C++ 2011. El literal 2147483648
, que no cabe en una longitud de 32 bits, se trata como unsigned long
, al menos en mi sistema de 32 bits. (Eso está bien para C++ 98 o C++ 2003; el comportamiento no está definido, por lo que el compilador puede hacer lo que quiera).)
Así dado un típico de 32 bits de complemento a 2 int
tipo, esto:
cout << -2147483647 << '\n';
toma el valor int
2147483647
, lo niega, e imprime el resultado, que coincide con el resultado matemático que cabría esperar . Pero esto:
cout << -2147483648 << '\n';
(cuando se compila con gcc 4.6.1) toma el valor long
o unsigned long
2147483648
, niega que como un unsigned int, produciendo 2147483648
, e imprime eso.
Como han mencionado otros, puede usar sufijos para forzar un tipo particular.
Aquí es un pequeño programa que se puede utilizar para mostrar cómo sus compilador trata literales:
#include <iostream>
#include <climits>
const char *type_of(int) { return "int"; }
const char *type_of(unsigned int) { return "unsigned int"; }
const char *type_of(long) { return "long"; }
const char *type_of(unsigned long) { return "unsigned long"; }
const char *type_of(long long) { return "long long"; }
const char *type_of(unsigned long long) { return "unsigned long long"; }
int main()
{
std::cout << "int: " << INT_MIN << " .. " << INT_MAX << "\n";
std::cout << "long: " << LONG_MIN << " .. " << LONG_MAX << "\n";
std::cout << "long long: " << LLONG_MIN << " .. " << LLONG_MAX << "\n";
std::cout << "2147483647 is of type " << type_of(2147483647) << "\n";
std::cout << "2147483648 is of type " << type_of(2147483648) << "\n";
std::cout << "-2147483647 is of type " << type_of(-2147483647) << "\n";
std::cout << "-2147483648 is of type " << type_of(-2147483648) << "\n";
}
Cuando compilo, consigo algunas advertencias:
lits.cpp:18:5: warning: this decimal constant is unsigned only in ISO C90
lits.cpp:20:5: warning: this decimal constant is unsigned only in ISO C90
y la siguiente salida, incluso con gcc -std=c++0x
:
int: -2147483648 .. 2147483647
long: -2147483648 .. 2147483647
long long: -9223372036854775808 .. 9223372036854775807
2147483647 is of type int
2147483648 is of type unsigned long
-2147483647 is of type int
-2147483648 is of type unsigned long
me da la misma salida con VS2010, al menos con defau Configuraciones
Interesante, aquí está el desmontaje: cout << -4294967293 << '\ n'; push 0Ah mov es, esp push 3 Observe que empuja 3 como inmediato de inmediato. (VS2010 ultimate) – ScarletAmaranth
El operador de flujo de 'std :: cout' probablemente no esté promocionando esos literales como era de esperar. – AJG85
@ScarletAmaranth Creo que está bien, porque 4294967293 se lee primero como unsigned int y que negated, que rinde 3. No estoy seguro aunque – hirschhornsalz