【问题标题】:Does EOF set errno?EOF 是否设置 errno?
【发布时间】:2014-05-01 08:47:42
【问题描述】:

我总是为系统调用的返回值而苦恼——它们是如此的不一致! 通常我会检查它们是 NULL 还是 -1,然后调用 perror。但是,对于 fgets,手册页显示:

gets()fgets() 成功返回 s,NULL 出错或在未读取字符时出现文件结尾。

这意味着返回值NULL 不一定是错误 - 它也可以是 EOF。到达文件末尾时是否设置了errno?在这种情况下我还能打电话给perror吗?

如果不是,判断调用是否返回错误而不是 EOF 的常用方法是什么。我想将perror 与NULL 字符串一起用于错误,并为EOF 使用自定义字符串。

【问题讨论】:

    标签: c unix system-calls


    【解决方案1】:

    根据 fputs 自己的文档,是的,EOF 确实设置了 errno。手册页间接地推断出它,而不是直接说明它,希望能得到修改。函数 fputs 返回一个整数,成功时为正数,失败时为 EOF。所以错误处理 fputs 的关键是设置一个代码块,在 fputs 被调用时检查它的返回值。以下是我被教导如何处理 fputs 错误的 sn-p。

    if (fputs(buffer, stdout) == EOF)
    {
      fprintf(stderr, "fputs returned EOF: %s\n", strerror(errno));
      // .. and now do whatever cleanup you need to do.
      // or be lazy and exit(-1)
    }
    

    这里我将缓冲区的内容写入标准输出并检查 fputs 是否返回 EOF。 EOF 表示设置了错误代码,因此只要您按照 fputs 手册页上的文档进行操作,您应该能够创建一堆 if 语句来检查 errno 可以设置的各种错误代码。

    (1) 什么是缓冲区?我在别处声明的一些字符数组。

    (2) fprintf 是做什么的?它将输出打印到传入的文件描述符,在这种情况下是标准错误(stderr ...它像标准输出一样打印到控制台,但是对于错误)。

    (3) 什么是strerror?它是在 string.h 标头中定义的函数,用于打印传入错误代码的错误信息。它包含可以设置 errno 的每个错误代码的信息。头文件 string.h 不应与 strings.h 混淆,后者是一个不包含 strerror(3) 的 BSD linux 头文件。

    编辑:好的,我搞砸了。您正在寻找有关 fgets 的答案,而不是 fputs。

    要检查 fget 是否有错误,请执行以下操作

    if (fgets(buffer, BUF_SIZE, myFile) == NULL)
    { 
      // print out error as a string to stderr
      fprintf(stderr, "fgets error occurred: %s\n", strerror(errno));
      // do cleanup
    }
    // special: you also need to check errno AFTER the if statement...
    

    问题是,您得到错误的唯一方法是如果流变得不可读,这可能是由于权限或试图读取处于写入模式的内容。在网络的情况下,可能会在阅读过程中切断您的连接,在这种情况下,您还需要检查 fgets if 语句之后的错误代码。但如果出现问题,它将设置错误代码。

    至少在手册页正确的情况下是这样。有关更多详细信息,请参阅 linux 手册页。唯一可以设置的错误码是“我看不懂这个东西”的代码,也就是errno == EBADF

    【讨论】:

    • 注意:1) OP 的帖子在fgets() 而不是fputs()。 2) 根据 C11 标准,fputs()errno 无关。也许它在 *nix 中确实如此。
    • @chux:C 标准并没有说fputs()errno 没有任何作用。它没有说它是否做任何事情。 N1570 7.5p3:“如果使用 errno,无论是否有错误,库函数调用都可以将 errno 的值设置为非零值b> 未记录在本国际标准的功能描述中。” POSIX specifies 一些errno 值可以由fputc 设置,因此也可以由fputs 设置。
    • 是的,我有点搞砸了。我在东西之间翻来覆去,误读了这个问题。你是对的。
    • @Keith Thompson 是的 - 比我对 errno 的评论说得好。
    • 一般来说,如果网络中断,对read() 的底层调用将一直阻塞,直到文件系统本身放弃(这可能会也可能不会导致当前进程进入磁盘睡眠) .另外,欢迎来到该网站,并感谢您在此答案上的努力 - 我认为您在这种风格下会做得很好。
    【解决方案2】:

    使用ferrorfeof 区分错误和EOF。如果有错误,没有一般的方法可以准确地找出错误是什么,但你可以知道有一个错误。

    标准 C (f)gets(和 (f)getc)不需要设置 errno,尽管符合标准的库实现可以将 errno 设置为几乎任意的非零值。

    Posix 确实要求 (f)get{c,s} 在读取错误时设置 errno,但这只会在您确定存在读取错误(通过调用 ferror)后帮助您。同样重要的是要记住,库函数永远不会将 errno 设置为 0,但可以将 errno 设置为非零值,即使没有发生错误也是如此。所以你不能测试errno来代替检查任何库函数的错误返回,包括fgets。而且由于文件结尾不是错误,errno 将(可能)不会在 EOF 上被修改,因此在这种情况下它的值是没有意义的。

    【讨论】:

    • @Xufeng:不,它直接从FILE对象获取信息,以某种特定于实现的方式。
    • @Xufeng: 不是真的,因为errno 还没有设置(至少,不是由ferror(f)gets 设置的),所以perror 的结果充其量只是误导.您所能做的就是打印一些本地化版本的I/O error,但是即使设置了errnoperror 也不会做得更好。
    • 哦,既然你说 fgets 没有设置 errno,所以我做了一些研究,发现 fgets 它一开始就不是系统调用.. :)
    • @Xufeng:是的,这是要记住的重要事情。系统调用在errno的使用上是一致的。但只有手册第 2 节中的函数是系统调用。 getsfgets 是标准 C 库函数,标准 C 库是可移植的,并且对存在诸如 errno 之类的特定于 unix 的接口一无所知。
    • @JanHudec:标准 C 包含头文件 <errno.h> 的定义,其中包括 errno 的定义:“...扩展为具有 int 类型和线程本地存储的可修改左值持续时间,其值由几个库函数设置为正错误数。”一个这样的函数是strtod,它也不是系统调用。
    猜你喜欢
    • 1970-01-01
    • 2012-05-27
    • 2021-01-06
    • 2021-05-18
    • 1970-01-01
    • 2013-08-23
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    相关资源
    最近更新 更多