EOF解惑

来源:互联网 发布:淘宝正品代购可信吗 编辑:程序博客网 时间:2024/06/05 06:26

EOF,end of file的缩写,表示"文字流"(stream)的结尾。这里的"文字流",可以是文件(file),也可以是终端tty。

代码中经常见到如下处理:

  int c;
  while ((c = fgetc(fp)) != EOF) {

    putchar (c);

  }

那么是不是每个文件末尾都存放着一个EOF, 作为文件结束的标志呢,就跟回车换行一样,于是查看了一下EOF的定义:

# define EOF (-1)

也就是0xFF,如果是这样的话文件中就不能出现0xFF了,否则就会被认为文件结束的标志,首先想到的就是转义,比如两个0xFF 0xFF代表本意0XFF,但是对于二进制文件,比如可执行程序,这显然是行不通的,所以说在文件结尾并不存在EOF字符。

于是决定阅读一下libc的源代码,在fgetc的实现中找到如下代码:

..............

if (__stdio_READ(stream, &uc, 1)) {
return uc;
}

.............

return EOF;

其中__stdio_READ()定义如下:

if ((rv = __READ(stream, (char *) buf, bufsize)) <= 0) {
if (rv == 0) {
__STDIO_STREAM_SET_EOF(stream);
} else {
/* if (errno == EINTR) goto RETRY; */
__STDIO_STREAM_SET_ERROR(stream);
rv = 0;
}

可以看出当read返回为<=0时,返回EOF, 其中read返回为0就表示文件到达末尾没有数据可读了,返回负数表示读取出错了。

所以fgetc正常情况下返回的是读取到的单个字符,但是如果读取到的字符本身就等于0xFF,应该要跟EOF区分才行,通过查看fgetc的原型发现了其中的奥秘:

int __fgetc_unlocked(FILE *stream)

读取到的都是单个char为何返回值为Int型呢,其实目的就是为了区别0xFF和EOF,因为读取到的都是unsigned char类型假设为0xmm,转换为Int类型都是0x00 00 00 mm, 是一个大于0的数, 如果是EOF,返回的是0xFF FF FF FF, 即-1,这样就可以区分出来了。

另外通过上面的分析可以看出返回EOF可能是到达文件末尾或者读取出错了,这样区分呢?个人认为可以改为文件末尾返回EOF,出错返回除EOF之外的其他负数,但是现在的实现并不是这样的,而是提供了另外两个函数:

feof() 判断是否到达了文件末尾

ferror() 判断是否读取出错

实现也很简单,前面读取异常是会设置标志__STDIO_STREAM_SET_EOF(stream)

原创粉丝点击