【问题标题】:Segmentation fault while using ferror() in a simple program. Why?在简单程序中使用 ferror() 时出现分段错误。为什么?
【发布时间】:2010-01-10 06:12:11
【问题描述】:

为什么下面的代码会出现分段错误?

#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *file;
    file = fopen("text","r");
    if (file == NULL) printf("Error READING FILE");
    if (ferror(file)) printf("error reading file");    //line 9
    return 0;
}

在 gdb 中进行回溯会得到:-

> #0 0x00007ffff7ad9d30 in ferror () from /lib/libc.so.6 > #1 0x00000000004005fa in main () at test.c:9

【问题讨论】:

  • 为什么你发现文件是NULL后还要继续执行?

标签: c gdb


【解决方案1】:

文件为空。您没有看到第一个 printf 因为程序在刷新标准输出之前崩溃。

【讨论】:

  • 如果我在第 9 行之前添加:- fflush(stdout),我会得到输出。但是,只是为了我想知道的信息,什么时候在程序中刷新标准输出?
  • 当你打印一个换行符*,或者缓冲区已满,或者程序结束时。 (*):默认情况下,stdout 在大多数系统上是行缓冲的。您还应该在stderr 上打印错误消息:通常它是无缓冲的(但更重要的是,错误消息应该发送到stderr,而不是stdout)。
  • @Alok 感谢回复.. 正是我所问的。
【解决方案2】:

如果fopen 返回NULL,则文件未打开;您将NULL 传递给ferror,这是无效的。您没有要传入的打开文件;这就是NULL 的意思,它不能给你一个文件指针。 ferror 用于获取与读取和写入文件相关的错误,一旦它实际被打开并且你有文件可以使用。

如果fopen 失败,并且您想获得更多关于原因的信息,您需要检查errno global variable,在errno.h 中定义。

#include <errno.h>

// ...snip...

if (file == NULL) 
  printf("Error READING FILE: %s\n", strerror(errno));

这个例子展示了如何获取描述错误的字符串;您还可以将errno 中的值与它可能具有的值之一进行比较,并根据错误的内容做一些不同的事情。请参阅fopen man pagePOSIX spec,以获取要比较的可能错误列表。以下是检查各种可能错误的方法:

if (file == NULL) {
  int error = errno;  // copy it so other calls like printf don't modify it
  printf("Error READING FILE: %s\n", strerror(error));
  switch (error) {
  case EACCESS:
    // access was denied
    break;
  case ENOENT:
    // the file or one of its ancestors doesn't exist
    break;
    // etc...
  }
}

(这是我最初在另一个答案的评论中写的内容的扩展)

【讨论】:

  • +1,很好的答案。请注意,C 标准不需要 fopen 设置 errno(POSIX 需要)。您应该在调用fopen() 之前将errno 设置为0,“以防万一”。此外,errno 可能是也可能不是全局变量:它是一个可修改的左值,如果库以这样的方式实现它,它可能由函数调用产生。
  • 感谢您的澄清,阿洛克。我想提到errno 实际上并不是一个全球性的,但我认为这比启发性更令人困惑。我不知道C不需要fopen来设置errno;我编写的大多数 C 代码是在 Linux、Mac OS X 或 BSD 上编写的,因此我倾向于更关注手册页和 POSIX,而不是 C 标准。很高兴知道这种假设不一定是可移植的。
  • 是的 - 我也将其视为实施质量问题 - 所以很难找到一个不设置 errno 的好库,特别是因为 POSIX 需要它。
【解决方案3】:

如果文件在第 9 行等于 NULL,则在 ferror() 调用期间将发生 Seg Fault。

如果文件为 NULL(在第 8 行确定),则不应执行第 9 行。

您的第 8 行代码应该这样更改:

if (file == NULL)
{
    printf("Error READING FILE");
    return 1;
}

注意:我可能对此非常错误,自从我完成 C/C++ 以来已经有一段时间了

【讨论】:

  • 或者将第9行改为else if ...
  • 我认为可以使用 ferror() 来检查文件是否可以成功打开。但是,它在打开文件并检查进一步的错误(如果有的话)后使用。我是对的吗?
  • ferror() 检查流以查看是否已设置错误指示符(在流上)。传递 NULL 流将产生 seg 错误。 cplusplus.com/reference/clibrary/cstdio/ferror
  • Shadyabhi: 如果fopen 返回NULL,那么文件没有打开;您将NULL 传递给ferror,这是无效的。您没有要传入的打开文件;这就是NULL 的意思,它不能给你一个文件指针。 ferror 用于获取与读取和写入文件相关的错误,一旦它实际被打开并且你有文件可以使用。
  • 如果文件无法成功打开,则说明您没有有效的FILE * 值。那么,你会怎么称呼ferror()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多