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
失敗した理由を説明するために使用する呼び出しの 1 つである場合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()
。ただし、失敗した関数と例外をキャッチしてログに記録する場所との間には通常かなりのギャップがあるため、それも望ましくありません。
現在、C では、C++ 例外のように追加情報をスタックに渡す方法がありません。そのため、C では、実際に失敗した関数と、失敗した場所のコンテキストをログに記録することがより重要です。