web-dev-qa-db-ja.com

UNIXのerrnoを対応する文字列に変換する方法は?

UNIXには、errnoを対応する文字列に変換する関数がありますか? EIDRMから「EIDRM」。これらの整数errnoのエラーをチェックするためにデバッグするのは非常に面倒です。

39
avd

strerror()が実行する必要があります。 http://linux.die.net/man/3/strerror

参考までに、これらのことを自分で簡単に見つけられるようにしてください。manerrno(または調査している関数)と入力し、manページの一番下を見ると、関連する関数のリストが表示されます。それらのそれぞれをmanする場合(名前に基づいて最初に何を行うかを推測して)、同様の質問に対する答えを見つけることがよくあります。

69
atk

あなたが持っている問題を正確に解決するちょうど別の解決策ですが、Python Cではなく:

>>> import errno
>>> errno.errorcode[errno.EIDRM]
'EIDRM'
12

Moreutilsパッケージで配布されるerrnoユーティリティがあります。

5

そのようなenumスタイルの名前についてはわかりませんが、デバッグとエラー報告の目的で perror(3) または strerror(3) 人間が読める形式のエラーコードを返すC関数。詳細については、manページを参照してください。

4

実際にEIDRMが必要で、そのエラー文字列は必要ない場合:いいえ。ただし、OpenBSDでは

man errno|egrep ' [0-9]+ E[A-Z]+'|sed 's/^ *//'|cut -d' ' -f1,2

「...\n89 EIDM\n ...」のニーステーブルを出力します。このテーブルは、この関数を組み込みたいプログラミング言語のデータ構造にさらに変換できます。

3
ayrnieu

UNIXでこれを行うための標準機能はありません。

しかし、私は最近 the errnoname library と書きました。これは、まさにこれを行うerrnoname関数を持っています。

strerror(またstrerror_rstrerror_lperror)エラーが何であったかについての「人間に優しい」ヒントを出力しますが、それらの出力は

  • 通常は文書化されていませんが、
  • 標準化されていない、
  • 長さや形式の制約に従うことが保証されていない、
  • 多くの場合、ロケール設定によって異なります。
  • すべての状況で常に意味があるとは限りません(たとえば、それらはFile exists for EEXIST。ただし、ファイルではない場合にエラーが返されることがよくあります)。

つまり、表面的にはユーザーフレンドリーですが、

  • 他のコードはそれらを確実に解析できません(自動化、監視、スクリプト、ラッパープログラムなどに悪い)、
  • エッジのケースで誤解を招く可能性がある、および
  • 技術経験のあるユーザーの邪魔になります。

皮肉なことに、これらの関数がすべての状況でエラー文字列としてerrnoシンボリック名を使用することを防止防止することは何もありません。特別なCロケールのように、特定のロケールに対してのみ実行した場合。しかし、私が知っているlibcはこれを行いません。

とにかく、私のerrnonameは、寛容なライセンスである "Zero-Clause BSD License"(0BSD)、またはより正確にはパブリックドメイン相当のライセンスの下でリリースされているため、好きなことを何でもできます。

この回答をスタンドアロンにして、回答文字の制限内に収めるには、以下にerrnoname関数の2つの省略形を示します。

errnonameではどちらも実装されていますが、ここでは読みやすくするためにそれぞれの要点を分離しました。

いくつかのメモ:

  1. これは、2020年1月の開始時点でのLinux、Darwin(Mac OS XおよびiOS X)、FreeBSD、NetBSD、OpenBSD、DragonflyBSD、およびいくつかのクローズドソースUnixのerrno名のすべてまたはほとんどをカバーしています。

  2. 名前がわからないerrno値を指定すると、nullポインタが返されます。

バリエーション1:シンプル、ユニバーサル

これは非常に移植可能でシンプルであり、心配するEdgeケースはありません。それはあなたがそれに投げかけることができるほぼすべてのC89以上のコンパイラでコンパイルされます。 (おそらくC++コンパイラーでさえ、言語が分かれるにつれてますます珍しくなっています。)

このバリアントcanは、最適化が十分に高くなっている場合に、最新のコンパイラで非常に効率的なコード(switchステートメントではなく配列ルックアップ)にコンパイルされますが、正確な状況に依存しません。

#include <errno.h>

char const * errnoname(int errno_)
{
    switch(errno_)
    {
#ifdef E2BIG
        case E2BIG: return "E2BIG";
#endif
#ifdef EACCES
        case EACCES: return "EACCES";
#endif
/*
    repeat for the other 100+ errno names,
    don't forget to handle possible duplicates
    like EAGAIN and EWOULDBLOCK
*/
    }
    return 0;
}

バリエーション2:明らかに効率的で、ほとんどのシステムに適している

これは明らかに効率的であり、配列のルックアップを明示的にし、コンピューターの最適化に依存しないため、非常に確実に効率的なコードにコンパイルされます。

システムが正で、比較的小さく、適度に連続したerrno値を持っている限り、安全に使用できます。

配列の順序指定されていない指定された初期化子を実装するコンパイラでのみコンパイルできます(これまでのすべてのC++バージョンを除くC99以降)。

#include <errno.h>

char const * errnoname(int errno_)
{
    static char const * const names[] =
    {
#ifdef E2BIG
        [E2BIG] = "E2BIG",
#endif
#ifdef EACCES
        [EACCES] = "EACCES",
#endif
/*
    repeat for the other 100+ errno names,
    don't forget to handle possible duplicates
    like EAGAIN and EWOULDBLOCK
*/
    };
    if(errno_ >= 0 && errno_ < (sizeof(names) / sizeof(*names)))
    {
        return names[errno_];
    }
    return 0;
}
1
mtraceur