В книге Бьярна Страуструпа Принципы и практика программирования с использованием C ++ (шестой выпуск, ноябрь 2012 г.) , if (cin)
и if (!cin)
вводятся на стр. 148 и серьезно используются на стр. 178. while (cin)
вводится на стр. 183 и серьезно используется на стр. 201.
Однако мне кажется, что я не совсем понимаю, как работают эти конструкции, поэтому я их исследую.
Если я скомпилирую и запустил это:
int main()
{
int i = 0 ;
while (cin) {
cout << "> ";
cin >> i ;
cout << i << '\n';
}
}
Я получаю что-то вроде:
$ ./spike_001
> 42
42
> foo
0
$
- Почему при вводе "foo" для
i
устанавливается значение0
? - Почему при вводе "foo"
cin
устанавливается наfalse
?
В качестве альтернативы, если я запустил и скомпилирую это:
int main()
{
int i = 0 ;
while (true) {
cout << "> ";
cin >> i ;
cout << i << '\n';
}
}
Я получаю что-то вроде:
$ ./spike_001
> 42
42
> foo
> 0
> 0
...
Последняя часть пользовательского ввода здесь - foo
. После этого строка > 0
повторно выводится программой на стандартный вывод, пока не будет остановлена с помощью Ctrl + C.
- Опять же, почему при вводе "foo" для
i
устанавливается значение0
? - Почему пользователю не предлагается ввести новое значение для
i
на следующей итерации цикла while после вводаfoo
?
Это использует g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
.
Прошу прощения за такой длинный вопрос, но я думаю, что все сводится к следующему: «Как оценивается cin?»
2 ответа
Что ж, std::cin
(или, точнее, std::basic_ios
) имеет operator bool
для неявного преобразования std::cin
в bool
по запросу (например, в вашей оценке if
).
Семантика следующая:
Проверяет, нет ли в потоке ошибок. Возвращает
true
, если поток не содержит ошибок и готов к операциям ввода-вывода. В частности, возвращает!fail()
.
Почему при вводе "foo", по-видимому, i устанавливается в 0?
Опять же, почему ввод "foo", по-видимому, приводит к тому, что i устанавливается в 0?
Поскольку operator>>
в int
ожидает целое число в строке.
Из cppreference
:
Если извлечение не удается (например, если была введена буква, где ожидается цифра), значение остается неизменным, и бит сбоя устанавливается.
Почему при вводе «foo» для cin устанавливается значение false?
Поскольку бит ошибки установлен, поэтому fail()
возвращает true
.
Почему пользователю не предлагается ввести новое значение для i на следующей итерации цикла while после ввода foo?
Это потому, что std::cin
имеет установленный бит ошибки, поэтому он не может получить ввод и просто печатает старое значение i
, которое равно 0
.
42
на 0
.
Когда вы используете оператор >>
в потоке, он пытается извлечь значение этого типа из строки. Другими словами, когда вы выполняете cin >> i
, где i
- это int
, поток пытается извлечь int
из потока. Если это удается, i
устанавливается на извлеченное значение, и все в порядке. Если это не удается, устанавливается badbit
потока. Это важно, потому что обработка потока как bool эквивалентна проверке, установлен ли он badbit
(if (cin)
похож на if (cin.good())
).
Так или иначе ... что происходит, так это то, что foo устанавливает плохой бит, поскольку извлечение не удается. На самом деле, вы должны проверить, успешно ли извлекается напрямую:
if (cin >> i) { /* success */ }
Что касается качества кода, я подозреваю, что вы используете using namespace std;
. Помните, что это может быть опасным.
if (cin >> i)
уже имел интуитивно понятный для меня смысл, но хотя Страуструп использует его в некоторых случаях, это не то, что он использует в своих примерах на страницах, которые я упомянул. Поскольку я хочу понять все примеры, это означает, что мне также нужно понимать if (cin)
и while (cin)
.
operator>>
в потоках фактически возвращает себя. Таким образом, возврат cin >> i
равен cin
. Это то, что позволяет выполнять неявное логическое преобразование и позволяет создавать более сложные цепочки, такие как cin >> i >> s >> f >> ...
.
Похожие вопросы
Связанные вопросы
Новые вопросы
c++
C++ — это язык программирования общего назначения. Изначально он разрабатывался как расширение C и имел аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде, который будет скомпилирован с помощью компилятора C++. Используйте тег версии для вопросов, связанных с конкретной стандартной версией [C++11], [C++14], [C++17], [C++20] или [C++23]. и т.д.
"foo"
в целое числоi
.cin
обычно выполняет преобразования типов, необходимые при использовании оператора>>
, но нет способа преобразовать"foo"
в целое число.