当 >> 运算符试图输入一个大于变量可以包含的值时会发生什么?
What happens when >> operator is trying to input a value bigger than a variable can contain?
我正在从文本文件中提取数字并用它们填充一个 int 类型的数组。
我在使用这些代码行循环遍历 .txt 文件时将值插入数组(其中 k 是 .txt 文件中的数字数量):
for (int j = 0; j < k; j++)
inputFile >> tab[j];
当文本文件中的数字小于整数类型的最大大小 2,147,483,647 时,一切顺利。
当数字大于这个数字时,我认为程序会溢出并且无法插入它,但之后它也无法插入任何数字。
是什么导致溢出后不再插入数字?
未定义的行为。算术溢出可能会被默默地忽略,或者可能会导致发出终止程序的信号,具体取决于实施质量。
标准要求,如果输入值超出范围,则将最近的可用值写入目标,并设置流的 failbit
。具体要求(来自[istream.formatted.arithmetic]/3)是:
operator>>(int& val);
The conversion occurs as if performed by the following code fragment [...]:
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);
一旦设置了流的失败位,它就是 "sticky",因此在清除失败位之前,进一步提取数据的尝试都会立即失败。
在 std::istream& std::istream::operator>>(std::istream&, int&)
上,cppreference 说:
Behaves as a FormattedInputFunction. After constructing and checking the sentry object, which may skip leading whitespace, extracts an integer value by calling std::num_get::get()
...
If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max()
or std::numeric_limits<T>::min()
is written and failbit flag is set. (since c++11)
它不是规范的,但它确实提供了对这里发生的事情的一个体面的总结。
FormattedInputFunctions 将从流构造一个哨兵并检查值。如果哨兵对象的计算结果为 false
,则 no input is performed.
如果among other situations正在操作的流设置了故障位,则哨兵对象将评估为false
。
所以,发生的事情是这样的:
- 流试图读入一个太大而无法容纳在
int
数据类型中的整数。
- 传入其函数的
int
设置为 int
可以存储的最大可能值。
- 传入函数的流设置了失败位。
- 进一步读取流失败并且什么都不做,因为流的 failbit 已设置。
您可以通过在执行读取操作后检查整数的失败位和值来检测这些溢出错误,如问题 Read int from istream, detect overflow.
的已接受答案中所述
您可以通过使用 std::basic_ios::clear
取消设置 故障位来从这些错误中恢复。在调用取消设置 failbit 的 clear
之后,进一步的读取将按照您的预期进行。
我正在从文本文件中提取数字并用它们填充一个 int 类型的数组。
我在使用这些代码行循环遍历 .txt 文件时将值插入数组(其中 k 是 .txt 文件中的数字数量):
for (int j = 0; j < k; j++)
inputFile >> tab[j];
当文本文件中的数字小于整数类型的最大大小 2,147,483,647 时,一切顺利。
当数字大于这个数字时,我认为程序会溢出并且无法插入它,但之后它也无法插入任何数字。
是什么导致溢出后不再插入数字?
未定义的行为。算术溢出可能会被默默地忽略,或者可能会导致发出终止程序的信号,具体取决于实施质量。
标准要求,如果输入值超出范围,则将最近的可用值写入目标,并设置流的 failbit
。具体要求(来自[istream.formatted.arithmetic]/3)是:
operator>>(int& val);
The conversion occurs as if performed by the following code fragment [...]:
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);
一旦设置了流的失败位,它就是 "sticky",因此在清除失败位之前,进一步提取数据的尝试都会立即失败。
在 std::istream& std::istream::operator>>(std::istream&, int&)
上,cppreference 说:
Behaves as a FormattedInputFunction. After constructing and checking the sentry object, which may skip leading whitespace, extracts an integer value by calling
std::num_get::get()
...
If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value,
std::numeric_limits<T>::max()
orstd::numeric_limits<T>::min()
is written and failbit flag is set. (since c++11)
它不是规范的,但它确实提供了对这里发生的事情的一个体面的总结。
FormattedInputFunctions 将从流构造一个哨兵并检查值。如果哨兵对象的计算结果为 false
,则 no input is performed.
如果among other situations正在操作的流设置了故障位,则哨兵对象将评估为false
。
所以,发生的事情是这样的:
- 流试图读入一个太大而无法容纳在
int
数据类型中的整数。 - 传入其函数的
int
设置为int
可以存储的最大可能值。 - 传入函数的流设置了失败位。
- 进一步读取流失败并且什么都不做,因为流的 failbit 已设置。
您可以通过在执行读取操作后检查整数的失败位和值来检测这些溢出错误,如问题 Read int from istream, detect overflow.
的已接受答案中所述您可以通过使用 std::basic_ios::clear
取消设置 故障位来从这些错误中恢复。在调用取消设置 failbit 的 clear
之后,进一步的读取将按照您的预期进行。