2012-07-10 8 views
9

通常の場合、open()は新しいファイル記述子を返します。エラーが発生した場合は-1を返し、その場合はerrnoが適切に設定されます。なぜfopen()またはopen()がエラーコードを返す代わりにerrnoを使用するのですか?

なぜこのerrnoのメカニズムが使用されているのか理解していませんか?ここの目的は何ですか?なぜ私たちはいくつかの負の戻り値なしですべてのエラーをマップできないのですか? errnoメカニズムのいずれかのbenifitは

fd = open("/dev/tty0", O_RDWR | O_SYNC); 
if(fd == -1) 
    printf("this is EACCES error"); 
else if (fd == -2) 
    printf("this is EPERM error"); 

よう

ありますか。?もしそうなら、私はこのメカニズムを使用することができます他のもので知っている/理解したいと思います。

答えて

11

fopenFILE*戻りますので、現在のセマンティクスを使用すると、ユニバーサルパターンを採用することができますそのポインタにエラーコードを返すとは期待できません。ポインタの唯一の「特別な」値は0です。

ご覧のとおり、openの場合、この制限は適用されません。実際、Linuxのようなシステムは、あなたが自分の下位レベルで提案したことを正確に行います。フードの下のシステムコールは、何かがうまくいかない場合、負のエラーコードを返します。その(否定された)コードは、浅いユーザースペースラッパーによってerrnoに接続され、アプリケーションにエラーを示す-1を返します。

これが行われる理由は、純粋に歴史的なものです。古い時代にはスレッディングがなく、errnoは単純なグローバル変数でした。当時、選ばれた戦略はあまりオーバーヘッドにならず、おそらくOSとアプリケーションの間で通信するための受け入れ可能な方法と思われました。このようなインターフェースは基本的に多くのコードを壊すことなく変更することができないので、スレッドローカルの疑似変数としてerrnoに固執します。

これは理想的ではありませんが、これらは明らかにエラーの例外が発生するはっきりと表示されるため、オーバーヘッドはそれほど悪くありません。

+0

+1すてきな答え –

1

errnoはエラーコードです。実際に何が起こっているかにエラーをマッピングすることが重要で、コードで次の作業を戦略的に決定することができます。たとえば、ERANGEerrno.hで定義されていますが、strtol("0xfffffffff",NULL,0)の結果はその関数の範囲外です。さらに重要なことに、あなたの例では、EACCESまたはEPERMのエラーがあるかどうかを知っているので、ファイルの処理方法を知ることができます。

キャッチして処理したい問題が複数ある可能性があるため、すべての問題を1つのエラーコードでマップすることはできません。私がキャッチと言うとき、私は試してみる/キャッチを意味しません。

errnoを使用するとエラー処理メカニズムが使用されるため、-1よりも多くの情報が得られます。

ERANGE、EACCES、EPERMなどは、便宜上特定のエラー番号にマッピングされるマクロとみなされます。私にとって

9

利点は、整数を返しますが、fopenFILE *を返しますので、別の技術が使用されなければならないように、エラー情報がいくつかの負の値を返す、そのように統一され得ることがopenでOK働くだろうということです。

+0

FILE *はまだバッファ/メモリへのポインタなので、負ではありません。エラーが発生した場合、FILE *を負の値で返しますか? NULLが0であるため –

+6

ポインタは、少なくとも私が知っているアーキテクチャ上では、符号付きの概念がないため、「基礎となる符号なし整数」の全範囲をカバーすることができます(つまり、32ビットポイントは0x00000000から0xffffffffになります) 。そして、「NULL」はちょうど、「これは失敗しました、何が間違っているかを見るためにerrnoを見てください」と言うことです。 – fvu

+0

理論的には予約済みのポインタのセットも使用できます。必要なのは 'char err_ptrs [MAX_ERRNO];です。 void * EACCESS_ptr = err_ptrs + EACCESS; 'などを呼び出して、' EACCESS_ptr'にポインタの有効な "エラーコード"を設定します。しかし、整数やポインタとしてそれらを複製しなければならないことや、一部のインタフェースが整数値のスペース全体を有効なリターンとして使うという事実は、errnoを価値のあるものにします。 –

1

各関数に異なる戻り値を与えると、コードを一般的な方法で書くのが非常に複雑になります。あなたもマクロでこれをラップすることができます

int fd; 
if ((fd = some_function(arg1, arg2)) == -1) 
{ 
    perror("some_function"); 
    exit(1); 
} 

#define CALL_OR_DIE(function, ret, ...)  \ 
    if ((ret = function(__VA_ARGS__)) == -1) \ 
    { perror(#function); exit(1); } 

は使用方法:

int fd; 
CALL_OR_DIE(open, fd, "/dev/tty0", O_RDWR | O_SYNC); 
+1

だから基本的には、(1) '== -1'を' <0'(errnoを負と定義している)より書く方が良いです、そして、(2)これは 'errno'の動機ですか?私は、スレッドローカルの 'errno'から読み込むことができるので、失敗のケースで' fd'を 'perror'に渡す必要がないという利点があると思いますが、なぜerrnoがなぜそうでないのかは完全には分かりませんオープンからも戻った。 –

関連する問題