Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用fgetc时是否可能将EOF与正常字节值混淆?_C_Language Lawyer_Binaryfiles_Fgetc - Fatal编程技术网

使用fgetc时是否可能将EOF与正常字节值混淆?

使用fgetc时是否可能将EOF与正常字节值混淆?,c,language-lawyer,binaryfiles,fgetc,C,Language Lawyer,Binaryfiles,Fgetc,我们经常这样使用fgetc: int c; while ((c = fgetc(file)) != EOF) { // do stuff } 从理论上讲,如果文件中的某个字节的值为EOF,则该代码存在错误-它将提前中断循环并无法处理整个文件。这种情况可能吗 据我所知,fgetc在内部将从文件读取的字节强制转换为无符号字符,然后转换为int,并返回它。如果int的范围大于无符号字符的范围,这将起作用 如果不是(可能是sizeof(int)=1),会发生什么 fgetc有时会从文件中读取

我们经常这样使用
fgetc

int c;
while ((c = fgetc(file)) != EOF)
{
    // do stuff
}
从理论上讲,如果文件中的某个字节的值为
EOF
,则该代码存在错误-它将提前中断循环并无法处理整个文件。这种情况可能吗

据我所知,
fgetc
在内部将从文件读取的字节强制转换为
无符号字符,然后转换为
int
,并返回它。如果
int
的范围大于
无符号字符的范围,这将起作用

如果不是(可能是
sizeof(int)=1
),会发生什么

  • fgetc
    有时会从文件中读取等于
    EOF
    的合法数据吗
  • 它是否会改变从文件中读取的数据,以避免使用单一值
    EOF
  • fgetc
    是否为未实现的函数
  • EOF
    是否属于另一种类型,如
    long
我可以通过额外的检查使我的代码成为傻瓜:

int c;
for (;;)
{
    c = fgetc(file);
    if (feof(file))
        break;
    // do stuff
}

如果我想要最大的可移植性,这是必要的?

C规范规定
int
必须至少能够保存-32767到32767之间的值。任何具有较小
int
的平台都是非标准的

C规范还指出,
EOF
是一个负的
int
常数,
fgetc
在成功读取时返回“一个
无符号字符
转换为
int
”。由于
unsigned char
不能有负值,因此可以将
EOF
的值与从流中读取的任何值区分开来*

*请参见下文中的漏洞案例,在该案例中,这一点无法成立


相关标准文本(来自C99):

  • §5.2.4.2.1整数类型的大小

    实施定义值的大小(绝对值)应等于或大于所示值,且符号相同

    [……]

    • 类型为
      int
      INT\u MIN
      -32767

    • 类型为
      int
      INT_MAX
      +32767

  • §7.19.1
    -简介

    EOF
    。。。扩展为一个整型常量表达式,类型为
    int
    和一个负值,由多个函数返回以指示文件结束,即不再从流中输入

  • §7.19.7.1
    fgets
    功能

    如果未设置由
    stream
    指向的输入流的文件结束指示符,并且存在下一个字符,
    fgetc
    函数将该字符作为
    无符号字符
    转换为
    int
    并推进流的相关文件位置指示符(如果已定义)

如果
UCHAR\u MAX
INT_MAX
,没有问题:所有
unsigned char
值都将转换为非负整数,因此它们与EOF不同

现在,这里有一个有趣的漏洞:如果系统有
UCHAR\u MAX
INT\u MAX
,那么法律允许系统将大于
INT\u MAX
的值转换为负整数(根据§6.3.1.3,将值转换为无法表示该值的有符号类型的结果由实现定义),使从流中读取的字符能够转换为EOF


具有
CHAR\u BIT>8
的系统确实存在(例如,TI C4x DSP,它显然使用32位字节),尽管我不确定它们是否在EOF和流函数方面被破坏。

注意:chux的答案在大多数情况下都是正确的。我将这个答案留待讨论,因为我相信答案和评论中的讨论对于理解chux的方法是必要的(罕见的)情况是有价值的。

EOF保证有一个负值(C99 7.19.1),正如您所提到的,fgetc在转换为int之前会将其输入作为无符号字符读取。因此,它们本身保证EOF不能从文件中读取

关于你的具体问题:

  • fgetc无法读取等于EOF的合法数据。在文件中,没有签名或未签名的内容;它只是位序列。是C对10001111的解释不同,这取决于它被视为有符号还是无符号。fgetc需要将其视为无符号,因此不能返回负数(EOF除外)

    附录:它不能读取无符号字符部分的EOF,但当它将无符号字符转换为int时,如果int不能表示无符号字符的所有值,则行为由实现定义(6.3.1.3)

  • 托管实现的标准要求fgetc,但允许独立实现省略大多数标准库函数(有些显然是必需的,但我找不到列表)

  • EOF不需要很长的时间,因为fgetc需要能够返回它,而fgetc返回int

  • 就更改数据而言,它无法准确更改值,但由于fgetc被指定为从文件中读取“字符”,而不是从字符中读取,因此它可能一次读取8位,即使系统以其他方式将CHAR_位定义为16(如果sizeof(int),这是它可能具有的最小值)==1,因为5.2.4.2)要求INT_MIN=32767。在这种情况下,输入字符将被转换为始终具有高位0的无符号字符。然后它可以在不损失精度的情况下转换为int。(实际上,这不会出现,因为机器通常没有16位字节)

    • 是,
      c=fgetc(文件);如果(feof(file))
      对最大端口有效
      int c;
      for (;;)
      {
          c = fgetc(file);
          if (c == EOF) {
            if (feof(file)) break;
            if (ferror(file)) break;
          }
          // do stuff
      }