2011-12-14 4 views
10

В Visual Studio 2010 следующие программыбольшие отрицательные целые литералы

#include <iostream> 
using std::cout; 

int main() 
{ 
    cout << -2147483646 << '\n'; 
    cout << -2147483647 << '\n'; 
    cout << -2147483648 << '\n'; // numeric_limits<int>::min() 
    cout << -2147483649 << '\n'; 
    cout << -2147483650 << '\n'; 
    cout << "..." << '\n'; 
    cout << -4294967293 << '\n'; 
    cout << -4294967294 << '\n'; 
    cout << -4294967295 << '\n'; // -numeric_limits<unsigned int>::max() 
    cout << -4294967296 << '\n'; 
    cout << -4294967297 << '\n'; 
} 

генерирует следующий вывод

-2147483646 
-2147483647 
2147483648 
2147483647 
2147483646 
... 
3 
2 
1 
-4294967296 
-4294967297 

Что происходит?

Является ли это стандартным поведением или ошибкой Visual Studio?

Edit: Как несколько людей указали, что нет такого понятия, как отрицательного целого буквального. См. Отличный ответ Кит Томпсон ниже для более подробной информации.

+0

Интересно, здесь разборка: cout << -4294967293 << '\ n'; push 0Ah mov esi, esp push 3 Обратите внимание, что он сразу же нажимает 3. (VS2010 ultimate) – ScarletAmaranth

+0

Оператор потока 'std :: cout', вероятно, не продвигает эти литералы, как вы ожидали. – AJG85

+0

@ScarletAmaranth Я думаю, что все в порядке, потому что 4294967293 сначала читается как unsigned int и отрицается, что дает 3. Не совсем уверен, хотя – hirschhornsalz

ответ

16

-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'; 

принимает значение 2147483647int, сводит на нет его, и выводит результат, который соответствует математическому результату можно было бы ожидать , Но это:

cout << -2147483648 << '\n'; 

(при компиляции с GCC 4.6.1) принимает значение 2147483648long или 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 настройки.

+2

Но, как вы только что объяснили, целочисленный литерал никогда не является беззнаковым. 2147483648 должен иметь тип 'long long' здесь. –

+0

@Keith: Вы противоречите себе: «Обратите внимание, что он никогда не имеет неподписанного типа» и «принимает значение unsigned int 2147483648». Не могли бы вы прояснить? – user763305

+1

OOPS! Я исправлю это. –

2

Когда я компилирую это в GCC, я получаю следующее сообщение:

warning: this decimal constant is unsigned only in ISO C90 [enabled by default] 

Это происходит для каждой строки после (и в том числе)

cout << -2147483648 << '\n'; // numeric_limits<int>::min() 

Так что же происходит, компилятор ОБА Visual Studio и GCC позволяет нам писать эти литералы, и они просто рассматривают их так, как если бы они были отмечены как unsigned. Это объясняет поведение печатаемого текста, и это делает меня довольно уверенным, что вывод правильный (предположим, что мы разместили суффикс u на числах).

Мне все еще интересно, что -2147483648 не является допустимым символом целого числа со знаком, даже если он является допустимым знаковым целочисленным значением. Любая мысль о том, что кто-нибудь?

+3

'-2147483648' не является символом целого числа со знаком. '2147483648' - целочисленный литерал (постоянный, действительно), а' -' - унарный минус-оператор. –

+0

Возможно потому, что он читается как '2147483648', который существует только как без знака, а затем отрицается. – hirschhornsalz

+0

@ Джеймс: Спасибо, что нет. Я не знал, что '-' не является частью литерала –

Смежные вопросы