翻译《有关编程、重构及其他的终极问题?》——21.正确的检查文件的结尾符(EOF)

来源:互联网 发布:二维码点餐软件 编辑:程序博客网 时间:2024/04/19 07:55

翻译《有关编程、重构及其他的终极问题?》——21.正确的检查文件的结尾符(EOF)

标签(空格分隔): 翻译 技术 C/C++
作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
最后更新:2017年03月01日


21.正确的检查文件的结尾符(EOF)

让我们继续文件处理的话题,深入了解一下EOF。但这次我们会说说关于完全不同类型造成的bug,这通常会在部本地化版本的软件中发现。

下面这段代码来自Computational Network Toolkit。PVS-Studio诊断的错误说明为:V739 EOF should not be compared with a value of the ‘char’ type. The ‘c’ should be of the ‘int’ type(译者注:大意是EOF不能和char类型的值比较,应该和int类型比较)。

string fgetstring(FILE* f){  string res;  for (;;)  {    char c = (char) fgetc(f);    if (c == EOF)      RuntimeError("error reading .... 0: %s", strerror(errno));    if (c == 0)      break;    res.push_back(c);  }  return res;}

解释
让我们看看EOF是如何被声明的:

#define EOF (-1)

如你所见,EOF只不过是一个值为-1的整型。fgetc()函数返回一个整型的值,也就是说,它可以返回值为0到255(或-1)的数字。在上面的代码中这个值被转换为char类型,因此值为0xFF(255)就转为值为-1了(译者注:如果不明白,回去复习基础的二进制表达正数、负数的基本知识),所以-1也就作为了文件的结尾符进行处理(EOF)。

如果用户使用了扩展的ASCII码,当程序没有正确处理字母表中某一个符号时,也就会有遇到一个错误。

比如Windows 1251 code页,在俄文字母表中的最后一个字母值就是0xFF,因此,就被程序解释为文件的结尾符号。

正确的代码

for (;;){  int c = fgetc(f);  if (c == EOF)    RuntimeError("error reading .... 0: %s", strerror(errno));  if (c == 0)    break;  res.push_back(static_cast<char>(c));}

建议
其实我这里没有特别的建议,至于谈到EOF,我只是想展示一个比较有趣的错误的变化,因为部分人可能从来没有意识到。

记住,如果函数返回的是整型类型,不要马上把它转换为char类型,请停下来并确认相关代码都没有问题。顺便说一下,我们其实已经谈到过类似的问题,即在第二篇中讨论的memcmp()函数——“比0大的并不意味着就只是1”(其中的代码涉及到了MySQL)

0 0