Ответ 1
-2147483648
, например, не является целым литералом; это выражение, состоящее из унарного оператора -
, примененного к литералу 2147483648
.
До нового стандарта С++ 2011 С++ не требует наличия какого-либо типа размером более 32 бит (С++ 2011 добавляет long long
), поэтому литерал 2147483648
не переносится.
Двойной целочисленный литерал имеет первый из следующих типов, в котором его значение соответствует:
int
long int
long long int (new in C++ 2011)
Обратите внимание, что он никогда не имеет тип unsigned в стандартном С++. В версиях стандарта C (1998) и версии 2003 (не имеющих long long int
) в версиях стандарта 1998 и 2003 годов, десятичный целочисленный литерал, который слишком велик, чтобы соответствовать long int
, приводит к поведению undefined. В С++ 2011, если десятичный целочисленный литерал не помещается в long long int
, тогда программа "плохо сформирована".
Но gcc (по крайней мере, начиная с версии 4.6.1, последняя из которых у меня есть) не реализует семантику С++ 2011. Литерал 2147483648
, который не подходит для 32-разрядной длины, рассматривается как unsigned long
, по крайней мере, на моей 32-битной системе. (Это хорошо для С++ 98 или С++ 2003, поведение undefined, поэтому компилятор может делать все, что ему нравится.)
Таким образом, для типичного 32-битного типа 2's-complement int
это:
cout << -2147483647 << '\n';
принимает значение int
2147483647
, отрицает его и печатает результат, который соответствует ожидаемому математическому результату. Но это:
cout << -2147483648 << '\n';
(при компиляции с gcc 4.6.1) принимает значение long
или unsigned long
2147483648
, отрицает его как неподписанный int, уступая 2147483648
, и печатает это.
Как уже упоминалось, вы можете использовать суффиксы для принудительного создания определенного типа.
Здесь небольшая программа, которую вы можете использовать, чтобы показать, как ваш компилятор обрабатывает литералы:
#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";
}
Когда я его компилирую, я получаю несколько предупреждений:
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
и следующий вывод, даже с 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
Я получаю тот же вывод с VS2010, по крайней мере, с настройками по умолчанию.