给出以下片段:
#include <iostream>
#include <sstream>
int main()
{
std::stringstream str;
str.put('a');
str.put('\x80');
str.put('a');
str.ignore(32, '\x80'); // hangs
std::cout << str.tellg() << "\n";
}
如果使用 gcc 编译,标记的行会挂起,汇编单步执行表示无限循环。我在不同的操作系统上尝试了GCC 5.4、6.3、8.2、9.2,结果是相同的。 在 wandbox 上,也尝试了 clang (可能是 libc++ 而不是 libstdc++ 附带的),它正常终止。
只有当ignore的第二个参数是设置了MSB的字符,并且流中前后至少有一个字符时,才会发生这种情况。这是 libstdc++ 中的错误,还是标准禁止非 ascii 分隔符?
没有签名溢出,但问题与签名与未签名有关。
istream::ignore(n, delim)
的内部使用streambuf::sgetc()
检查下一个字符并将其与分隔符delim
进行比较。 sgetc()
对于 EOF 返回 -1,否则返回非负值。这意味着当它到达 '\x80'
字符 sgetc()
时,将返回 (int)(unsigned char)'\x80'
,即 128,并且永远不会与 delim
进行比较,即 -128。
这是 GCC 的 libstdc++ 中的一个 bug,它应该将
delim
字符转换为非负 int_type
,以便可以将其与 sgetc()
返回的值进行比较。