2016-03-09 5 views
1

Все, у меня есть код здесь, что я не могу объяснить поведение. Он размещен ниже. Я посмотрел на Why does integer overflow cause errors with C++ iostreams?, но на самом деле это не отвечает на мой вопрос.Неожиданное поведение от cin при переполнении int

#include <iostream> 
#include<stdio.h> 
using namespace std; 
int main() 
{ 
    int x; 
    scanf("%d", &x); 
    cout << "Value of x = " << x << endl; 
    cin >> x; 
    cout << "Failure Detected = " << cin.fail() << endl; 
    cout << "Value of x = " << x << endl; 
    return 0; 
} 

Итак, что я ожидал этот код, чтобы сделать для чтения в целом, распечатать значение этого целого, читайте в другом целом числе (в одной и то же переменное), и распечатать это целое. Если я введу ввод 7 и 2, то он работает так, как ожидалось. Однако, если я введу 2^31 (переполнение int на один) для первого и второго ввода, тогда первый вывод будет произносить «Значение x = -2147483648», а на втором выходе будет указано «Значение x = 2147483647». cin.fail() также вернет true. Что делает cin для ввода? Я думал, что если cin.fail() был истинным, значение x должно остаться без изменений. Если бы не остался незатронутым, я ожидал бы, что значение x переполнится как обычно (например, scanf). Что здесь происходит здесь? Почему он ограничивает значение при максимальном значении целого числа?

Заранее благодарен!

+0

Пожалуйста, не downvote за то, что очевидно; это на самом деле довольно тонко. – Bathsheba

ответ

3

В C++ 98 переменная не изменилась при неудачном вводе данных. Это был недостаток, если вы попытаетесь ввести неинициализированную переменную.

Например:

int a; 
cin >> a; 
cout << a; // UB if input failed! 

В более поздних стандартах переменный будет установлен в самом большом или минимально возможное значение, когда вход находится за пределами этого диапазона.


Для operator>>(int& val) стандарта говорит [istream.formatted.arithmetic]:

Превращение происходит, если выполняются с помощью следующего фрагмента кода (используя то же обозначение, как и для предыдущего фрагмента кода) :

typedef num_get<charT,istreambuf_iterator<charT,traits> > numget; 
iostate err = ios_base::goodbit; 
long lval; 
use_facet<numget>(loc).get(*this, 0, *this, err, lval); 
if (lval < numeric_limits<int>::min()) { 
    err |= ios_base::failbit; 
    val = numeric_limits<int>::min(); 
} else if (numeric_limits<int>::max() < lval) { 
    err |= ios_base::failbit; 
    val = numeric_limits<int>::max(); 
} else 
    val = static_cast<int>(lval); 
setstate(err); 
+0

«Стандарты: переменная будет установлена ​​на максимальное или минимальное значение». Соответствует ли стандартный мандат? Если это так, то мой ответ неточен. – Bathsheba

+0

Посмотрел. Вы правы. Приостановлено (и извинения за кражу вашего ответа). – Bathsheba

2
  1. Ваш scanf: Поведение на переполненном подписанный интегральный тип в C++ является неопределенными. Бессмысленно рассуждать о том, что происходит под капотом. «Переполнение как обычно» особенно бессмысленно.

  2. Ваш cin: Pre C++ 03, x не был бы изменен, если он не смог разместить вход. Таким образом, поведение последующего cout было бы undefined, так как вы будете читать неинициализированную переменную. Начиная с C++ 03, x закрывается (или покрывается полом) при его наибольшем (или наименьшем) значении, если его диапазон будет превышен. Это то, что происходит во втором случае.