提问人:Hyena 提问时间:1/14/2023 最后编辑:Hyena 更新时间:1/15/2023 访问量:85
std::ifstream gcount 文档中的“提取的字符数”是什么意思?
What is meant by "number of characters extracted" in the std::ifstream gcount doc?
问:
该方法的文档中说:ifstream::getline
此函数成功读取和存储的字符数可以通过调用成员 gcount 来访问。https://cplusplus.com/reference/istream/istream/getline/
在任何情况下,如果计数> 0,它将空字符 CharT() 存储到数组的下一个连续位置并更新 gcount()。https://en.cppreference.com/w/cpp/io/basic_istream/getline
从上述两个资源中可以推断出,即使在遇到文件末尾 (EOF) 后,也应该更改 gcount。这是因为任何案例都包括 EOF 案例,并且我们都知道更新只有在更改目标记录时才是更新。ifstream::getline
在方法的文档中说:ifstream::gcount
返回上次对对象执行的未格式化输入操作所提取的字符数。https://cplusplus.com/reference/istream/istream/gcount/
返回最后一个未格式化输入操作提取的字符数,如果该数字不可表示,则返回 std::streamsize 的最大可表示值。https://en.cppreference.com/w/cpp/io/basic_istream/gcount
如果是从 ifstream 中提取的字符数,那么 getline 的 CPlusPlus.com 文档一定是错误的,因为它指出“字符已成功读取和存储”。
此外,CppReference.com 是错误的,因为它指出“无论如何......更新 gcount()“,但当在行结束分隔符之前遇到 EOF 时,不会更新 gcount。
如果是写入 的数组缓冲区参数的字符数,则标准库存在错误。在执行期间,如果行过早地以文件结束 (EOF) 结束,则 null 字符将追加到数组缓冲区的末尾,但 gcount 不会相应地更新。ifstream::getline
ifstream::getline
下面是举例说明这种困境的代码。
#include <stdlib.h>
#include <iostream>
#include <array>
#include <fstream>
#include <limits>
#include <cstring>
int main(int argc, char **argv) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " file\n";
return EXIT_FAILURE;
}
std::array<char, 10> buf;
std::ifstream file;
file.open(argv[1], std::ifstream::in);
do {
file.clear();
file.getline(buf.data(), buf.size());
std::streamsize gcount = file.gcount();
if (file.bad() || gcount <= 0) {
break;
}
if (!file.fail()) {
std::cerr
<< "LINE: [" << buf.data() << "] gcount "
<< std::to_string(gcount) << ", strlen "
<< std::to_string(strlen(buf.data()))
<< (file.eof() ? " (EOF)\n" : "\n");
continue;
}
// Buffer must have got full. Let's skip to the end of line.
file.clear();
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
while (!file.eof() && !file.bad());
file.close();
return EXIT_SUCCESS;
}
这是我得到的文本文件的输出,该文件的最后一行末尾没有换行符。
LINE: [dgsagdsa] gcount 9, strlen 8
LINE: [test] gcount 5, strlen 4
LINE: [test123] gcount 8, strlen 7
LINE: [123test] gcount 8, strlen 7
LINE: [] gcount 1, strlen 0
LINE: [xxxxxxx] gcount 8, strlen 7
LINE: [yy] gcount 2, strlen 2 (EOF)
如您所见,在输出的最后一行,gcount 和 strlen 之间存在差异。
也就是说,现在让我们回到主要问题。
文档中提取的字符数是什么意思?std::ifstream::gcount
这个问题有两个部分。
- “角色”是什么意思?
- “提取”是什么意思?
在这种情况下,一个字符总是一个字节吗?Unicode 字符可以由多个字节组成。行尾序列也可以由多个字节 (CR+LF) 组成。是否会发生(也许在未来)gcount 增加 1 但提取了多个字节的情况?gcount 会不会增加 1 但数组缓冲区中存储了多个字节?
答:
让我们以示例中的最后一行为例,然后逐步完成它 - 。yy<eof>
initial state: gcount = 0, strlen(inProgressBuf) == 0
yy<eof>
gcount = 1, strlen(inProgressBuf) == 1
yy<eof>
^
gcount = 2, strlen(inProgressBuf) == 2
yy<eof>
^
oh, hit EOF
yy<eof>
^
在点击EOF时,已经提取了两个字符,2也是如此。 现在要在缓冲区中附加一个 null 字符 - 这与 无关。实际上只提取了两个字符。gcount
getline
gcount
对于带有分隔符的字符串,假设:yy<lf><eof>
initial state: gcount = 0, strlen(inProgressBuf) == 0
yy<lf><eof>
gcount = 1, strlen(inProgressBuf) == 1
yy<lf><eof>
^
gcount = 2, strlen(inProgressBuf) == 2
yy<lf><eof>
^
gcount = 3, strlen(inProgressBuf) == 2
yy<lf><eof>
^
当 LF 被命中时,正在从输入中提取一个字符,因此会递增。但是,提取的字符与分隔符匹配,因此不会将其添加到缓冲区中。只需为字符串的 null 终止添加 null 字符即可。gcount
getline
EOF
不是一个可以提取的字符,因此达到它不会递增。gcount
我能看到的唯一可能有争议的措辞是 https://en.cppreference.com/w/cpp/io/basic_istream/getline 的摘录:cppreference
在任何情况下,如果计数> 0,它将空字符 CharT() 存储到数组的下一个连续位置并更新 gcount()。
您可以将其解释为附加 null 字符是更新的原因。但是,我相信预期的含义是正在更新,因为.gcount
gcount
count > 0
关于如何确定写入的字节数的问题,评论中的建议似乎是合适的:
除非你击中 eof,否则它是
gcount
gcount + 1
评论
gcount + 1
gcount
gcount
Could it ever theoretically be that one character is extracted and two bytes are written into the array buffer?
是的,如果您的字符类型是 2 字节类型。CharT
gcount
gcount + 1
std::getline
characters
character
CharT
评论
getline
cplusplus.com
是错误的。我建议使用:en.cppreference.com/w/cpp/io/basic_istream/getlinecppreference.com
gcount
对分隔符进行计数,但该分隔符未写入数组。 不计算在内,因为不是从流中提取的字符。两者都不会添加到阵列中gcount
EOF
EOF