查看 stackoverflow 或其他地方的代码,我似乎很少看到 perror() 用于报告错误的确切性质。printf 更为常见。这是否表明 perror 有问题或缺失?我希望它可以更频繁地使用,因为它提供了更好的信息。
4 回答
我个人更喜欢strerror()
它做大致相同的事情,但允许您将错误消息与 printf 或类似函数一起使用,从而提供进一步的有用[对程序的编码员或用户,具体取决于错误的类型]。
例如:
errno = 0;
FILE *f = fopen(argv[1], "rb");
if (!f)
{
fprintf(stderr, "File %s open failed: error code %d ('%s')\n",
argv[1], errno, strerror(errno));
exit(1);
}
这样,我们也知道哪个文件(假设它是一个复制文件的程序,perror 不一定会告诉你它是“源”还是“目标”)。
如果错误是由于编程错误[或“预计不会出错的东西”],您还可以执行以下操作:
#define UNEXPECTED(cond) do { if (cond) { do_unexpected(errno, #cond, __FILE__, __LINE__); } while(0)
void do_unexpected(int err, const char* cond, const char *file, int line)
{
fprintf(stderr, "Unexpected error %s [errno=%d, errstr=%s] at %s:%d",
cond, err, strerror(errno), file, line);
exit(1);
}
errno = 0;
FILE *config = fopen("config.txt", "r");
UNEXPECTED(!config);
...
这是假设您不希望删除“config.txt”作为示例[这通常是非常糟糕的编程,但也许有一个正当的理由......]
perror() 不会准确地为您提供发生错误的行号,而您的 printf() 将帮助您识别正在打印的确切行。所以我认为它对调试更有帮助,我所知道的 perror() 没有错......
如果您errno
在进行标准库调用之前设置为零并且该调用失败并且它是errno
用于描述其失败原因的调用之一,那么perror
并且strerror
可能会提供有用的解释。大多数人不注意errno
,更不用说如何正确使用它了。这是更简单时代的产物。
由于我使用的是 C++,所以我不使用 printf() 和 co,并且经常在启动时调用 sync_with_stdio(false)。此外,该功能的问题在于它只允许在本地打印错误。我经常遇到的是这样的:
// setting errno
if(!foo1(bar))
throw_errno_exception("foo1");
// returning errorcode
if(int e = foo2(bar))
throw_exception(e, "foo2");
首先,不是每个函数都使用 errno。特别是对于新代码,我也不会这样做,而只是返回int
相应的错误代码。因此,对于那些“新”功能,我必须在使用之前手动设置 errno perror()
。但是,我也不希望这样,因为失败的函数和我捕获'n'记录异常的地方之间通常有很大的差距。
现在,在 C 中,您无法像在 C++ 异常中那样将附加信息向上传递。出于这个原因,在 C 中记录实际失败的函数和失败位置的任何上下文更为重要。