-2147483648
, например, не является целым литералом; это выражение, состоящее из унарного оператора -
, примененного к буквалу 2147483648
.
Перед новым стандартом C++ 2011 C++ не требует наличия какого-либо типа размером более 32 бит (C++ 2011 добавляет long long
), поэтому литерал 2147483648
не переносится.
десятичное число литерал первого из следующих типов, в которых его значение умещается:
int
long int
long long int (new in C++ 2011)
Обратите внимание, что это никогда не беззнакового типа в стандарте C++. В версиях стандарта C (1998) и 2003 года (которые не имеют long long int
), десятичный целочисленный литерал, который слишком велик, чтобы соответствовать long int
, приводит к неопределенному поведению. В C++ 2011, если десятичный целочисленный литерал не помещается в long long int
, тогда программа «плохо сформирована».
Но gcc (по крайней мере, с версии 4.6.1, последняя из которых у меня есть) не реализует семантику C++ 2011. Литерал 2147483648
, который не подходит для 32-разрядной длины, обрабатывается как unsigned long
, по крайней мере, на моей 32-битной системе. (Это хорошо для C++ 98 или C++ 2003, поведение не определено, поэтому компилятор может делать все, что ему нравится.)
Поэтому, учитывая типичный 32-битный 2's-дополнение int
типа, это:
cout << -2147483647 << '\n';
принимает значение 2147483647
int
, сводит на нет его, и выводит результат, который соответствует математическому результату можно было бы ожидать , Но это:
cout << -2147483648 << '\n';
(при компиляции с GCC 4.6.1) принимает значение 2147483648
long
или unsigned long
, сводит на нет его как беззнаковое 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, по крайней мере, с defau lt настройки.
Интересно, здесь разборка: cout << -4294967293 << '\ n'; push 0Ah mov esi, esp push 3 Обратите внимание, что он сразу же нажимает 3. (VS2010 ultimate) – ScarletAmaranth
Оператор потока 'std :: cout', вероятно, не продвигает эти литералы, как вы ожидали. – AJG85
@ScarletAmaranth Я думаю, что все в порядке, потому что 4294967293 сначала читается как unsigned int и отрицается, что дает 3. Не совсем уверен, хотя – hirschhornsalz