【问题标题】:C++ can native type char hold End of File character?C ++可以原生类型char保存文件结尾字符吗?
【发布时间】:2009-12-05 07:54:28
【问题描述】:

标题很清楚。

char c = std::cin.peek(); // sets c equal to character in stream

我刚刚意识到也许原生类型 char 不能容纳 EOF。

谢谢, 核磁共振

【问题讨论】:

  • 你能发布更多你的后期编辑循环吗?测试 eof 标志通常不是编写输入循环的最佳方法。检查peek()(或者更常见的是get()?)的返回值通常要好得多,因为许多人错误地认为eof() 将在下一次读取失败时返回true。这也意味着除了文件结尾之外,您不会检测到任何其他故障,并且可能会无限期地循环使用虚假数据。
  • 你在 eof 前面做得很好,因为你在循环之前和循环结束时“窥视”,但你仍然遇到任何非 eof 错误的问题。我仍然认为如果你只是在while条件下测试get()的返回值,它会更简单并且避免重复。使用get() 意味着您不必“忽略”,只需将读取的字符直接传递给“可扩展字符数组”即可。此外,为了获得最大的可移植性,您应该使用 ch = std::istream::traits_type::to_char_type( cin.get() ); 而不是隐式转换为 char,尽管这在大多数情况下都有效。

标签: c++ char eof


【解决方案1】:

简答:不。使用 int 而不是 char

稍微长一点的答案:不。如果你可以从函数中获取字符或值 EOF,例如 C 的 getchar 和 C++ 的 peek,显然普通的 char 变量不足以同时保存所有有效字符 EOF

更长的回答:视情况而定,但它永远不会像你希望的那样工作。

C 和 C++ 具有三种字符类型(“宽”类型除外):charsigned charunsigned char。普通 char 可以是有符号或无符号的,这因编译器而异。

EOF 的值是一个负整数,通常是 -1,所以很明显你不能将它存储在 unsigned char 或普通 char 未签名。假设您的系统使用 8 位字符(几乎所有字符都使用),EOF 将转换为(十进制)255,您的程序将无法运行。

但是如果你的 char 类型是有符号的,或者如果你使用 signed char 类型,那么是的,你可以在其中存储 -1,所以是的,它可以按住 EOF。但是,当您从文件中读取代码为 255 的字符时会发生什么?它将被解释为-1,即EOF(假设您的实现使用-1)。因此,您的代码不仅会在文件末尾停止读取,而且在找到 255 个字符时也会停止读取。

【讨论】:

  • 取决于您打开文件是作为 ascii 文件还是二进制文件读取。虽然从记忆中我从来不需要以 ASCII 格式打开文件,但总是以二进制格式打开。这放弃了 EOF 和人们定义为 EOF 的所有问题。虽然我对 EOF 的定义不是当 ASCII 文档声明 EOF 时,而是当您确实达到文件大小的末尾时。
  • @Chad:我想你在想别的东西。如果您以文本或二进制文件的形式打开文件,不会改变 EOF 值在 char 变量中的存储方式。
  • @Thomas:只有一个小细节:EOF 总是负数,通常 -1,但标准允许其他负数。
【解决方案2】:

注意std::cin.peek()的返回值实际上是std::basic_ios<char>::int_type类型,和std::char_traits<char>::int_type一样,是int而不是char

更重要的是,int 中返回的值不一定是从charint 的简单转换,而是在流中的下一个字符上调用std::char_traits<char>::to_int_typestd::char_traits<char>::eof() 的结果(定义为EOF)如果没有字符。

通常,这一切的实现方式与fgetc 将字符转换为unsigned char,然后将其转换为int 的返回值完全相同,这样您就可以将所有有效字符值与EOF 区分开来.

如果您将std::cin.peek() 的返回值存储在char 中,那么读取具有正值的字符(比如iso-8859-1 编码文件中的ÿ)将比较等于@987654338 @.

学究式的做法是。

typedef std::istream::traits_type traits_type;

traits_type::int_type ch;
traits_type::char_type c;

while (!traits_type::eq_int_type((ch = std::cin.peek()), traits_type::eof()))
{
    c = traits_type::to_char_type(ch);
    // ...
}

这可能更常见:

int ch;
char c;

while ((ch = std::cin.peek()) != EOF)
{
    c = std::iostream::traits_type::to_char_type(ch);
    // ...
}

请注意,正确转换字符值很重要。如果您执行这样的比较:if (ch == '\xff') ... 其中chint,如上所述,您可能不会得到正确的结果。您需要在字符常量上使用 std::char_traits<char>::to_char_typechstd::char_traits<char>::to_int_type 以获得一致的结果。 (不过,使用基本字符集的成员通常是安全的。)

【讨论】:

  • 我很欣赏这个答案,但它比我想要的要冗长一些,而且让我有些困惑。
  • 你能指出一些有用的地方或者我可以澄清的东西吗? SO 的目标是协作获得“最佳”答案,因此我们感谢任何改进帮助。
  • 我并没有质疑这些陈述的清晰性,我更多的是指的是我自己对语言的无知。我真的只是对 C++ 不够熟悉,以至于您的回答立即点击了我。我想我应该在我的问题开始时澄清我不太关心可移植性。
  • 我认为这是一个很好的答案,并且(对于 C++)在细节上比我的更正确。但它确实有点复杂,因为 C++ 是一种复杂的语言。我的意思是,std::char_traits::to_char_type!
猜你喜欢
  • 2014-09-30
  • 2012-10-26
  • 1970-01-01
  • 2014-10-13
  • 1970-01-01
  • 1970-01-01
  • 2010-12-09
  • 2019-07-13
相关资源
最近更新 更多