web-dev-qa-db-ja.com

失敗した場合のリターンコード。ポジティブかネガティブか?

linuxの特別な状況では、Cプログラムの実行に失敗する可能性があります。例:スペースを割り当てると、OSがそれを拒否します。

char *buffer = (char *) malloc(1024);
if (buffer == NULL)
    return ENOMEM;

この失敗は、OSに配信される戻りコードによって示されます。

  • 戻りコード0(EXIT_SUCCESS)は、正常な実行としてマークされます。
  • 0でない戻りコードは、失敗としてマークされます。

だから私の質問は、プログラムがエラーを検出したときの規則は何ですか。正または負のリターンコードを返す必要がありますか?

私の教授は、UNIX/Linuxでは常に、負のエラーコードを返すように言っていました。ただし、errno-Codeはすべて正の整数です。また、のEXIT_FAILUREのdefine-Statementは1、正の整数です。したがって、私のコードは次のようになります。

char *buffer = (char *) malloc(1024);
if (buffer == NULL)
    return -ENOMEM;

または上記のコードのように? Linux-Kernel-Modulesから、ほとんどの場合、失敗すると負のエラーコードが返されることがわかっています。

助けてくれてありがとう。

6
cominfotty

だから私の質問は、プログラムがエラーを検出したときの規則は何ですか?正または負の戻りコードを返す必要がありますか?

あなたにはその選択をする贅沢(または責任)がありません。一般的なCの観点から、選択は3つのカテゴリに分類されます。

  • 指定する終了ステータスは、0またはEXIT_SUCCESSのいずれかです(必ずしも区別できるとは限りません)。これは、正常に完了したことを示します。

  • 指定する終了ステータスはEXIT_FAILUREです。これは、完了に失敗したことを示します。

  • 指定する終了ステータスはそれ以外のものです。

ホスト環境に通知される結果は、すべての場合で実装定義ですが、最初は成功を伝えるものであり、2番目は失敗を伝えるものです。

現在、POSIX exit()セマンティクスを実装しているLinuxおよびその他のオペレーティングシステムでは、実装の定義が標準化されています。

Statusの値は、0EXIT_SUCCESSEXIT_FAILURE、またはその他の値ですが、最下位の8ビット(つまり、status & 0377)のみがwait()から使用できます。およびwaitpid();

IEEE Std 1003.1-2008、2016 Edition ;強調を追加)。これらは従来のUNIXセマンティクスです。指定した終了ステータスの最下位8ビットのみが重要であるため、符号は失われます。ただし、POSIXの現在のバージョンは次のように述べています。

完全な値は、waitid()から、およびSIGCHLDのシグナルハンドラーに渡されるsiginfo_tで入手できます。

したがって、負の数を探すことがわかっている場合は、親プロセスに負の数をcan伝達します。ただし、一般的には機能しません。特に、親プロセスがシェルの場合は機能しません。

私の教授は、UNIX/Linuxでは常に、負のエラーコードを返すように言っていました。

これは、関数main()以外の関数の戻りコードに関する指示のように聞こえますが、教授の意味についての2番目の推測の方が信頼性が高いと思う理由がわかりません。教授に直接説明を求めます。

ただし、errno-Codeはすべて正の整数です。

さて、あなたの教授と明確にするもう一つのことは、彼があなたに彼のクラスの関数を書くことをどのように期待するかについてあなたに特定の指示を与えていたかどうか(より可能性が高い)、または彼が一般的なCまたはPOSIX規則について主張していたかどうか(ありそうもない、それが真実ではない多くのPOSIX関数があるため)、または何か他のもの。

C標準ライブラリ関数はerrnoコードを返さないことに注意してください。失敗を示すコード(常にではありませんが、多くの場合、負の数)を返す場合、プログラマーは詳細な理由でerrno変数を調べる必要があります。関数の戻りコードは通常、その情報を伝達しません。 POSIXによって標準化されているが、C doでは標準化されていない一部の関数はerrnoコードを直接返します。明らかに、これらはあなたの教授の処方箋に従っていません。

errno値は、同じプログラムによって呼び出された関数間の通信用であり、プログラムの環境との通信用ではないことにも注意してください。これらはプログラムの終了ステータスとして使用するためのものではなく、特に、それらの値が8ビットに収まるという保証はありません(上記を参照)。

また、のEXIT_FAILUREのdefine-Statementは1、正の整数です。したがって、私のコードは次のようになります。

EXIT_FAILUREの値は実装に依存します。したがって、そこから実装固有の洞察のみを収集できます。ただし、ご覧のとおり、実装でのプログラムの失敗を示す汎用の終了ステータスは1です。

Linuxおよびその他のPOSIX(-ish)システムでは、シェルがステータス126〜255に特別な重要性を指定し、もちろんステータス0を成功として解釈するため、1〜125の障害ステータスを選択することでシェルとの最適な統合を実現します。

char *buffer = (char *) malloc(1024);
if (buffer == NULL)
    return -ENOMEM;

または上記のコードのように? Linux-Kernel-Modulesから、ほとんどの場合、失敗すると負のエラーコードが返されることがわかっています。

繰り返しますが、違います。 Errnoコードは、プログラムの終了コードとして使用するためのものではなく、かなり特殊な状況でのみ、否定的なステータスで終了しようとする必要があります。一般的な規則は、有益なエラーメッセージをstderrに書き込んでから(perror()はまさにこの目的を果たします)、ステータス1または(より良いのはIMO)EXIT_FAILUREで終了することです。

障害の性質を説明する終了コードを提供する場合は、プログラムごとに値と重要性を定義するのはあなた次第です。最高の互換性を得るには、1〜125しか使用できないことを覚えておいてください。

6
John Bollinger

プロセスmain()returnステートメント、またはexit()の呼び出しからのUNIX/Linuxの終了コードはunsigned0〜255の範囲。

関数から、任意のタイプにすることができます。多くのライブラリ関数は、エラー時に-1を返します。

ただし、これが常に可能であるとは限りません。特に、通常はポインタを返す関数はそうです。慣例により、これらの関数はエラー時にNULLを返します。例としては、fopen()およびmalloc()があります。

これらの戻りコードは、エラーが発生したことを示すだけであり、エラーが何であるかを示すものではありません。通常、(エラーの場合)グローバルerrnoも正のエラーコードに設定され、詳細情報が提供されます。 man errno を参照してください

2
cdarke

プログラムからさらに指定されていないエラーコードの規則は、_EXIT_FAILURE_を使用することです。これは、OSが障害終了コードとして認識する値に定義されます。

_errno.h_で定義されているマクロは、プロセスの戻りコードではなく、プログラム実行中のエラーのみを対象としています。標準ライブラリはそれらをグローバルerrnoに配置します。必要に応じて、関数からの戻りコードとして使用することもできます。それらのうちの3つは、C標準で指定されています:EDOMEILSEQ、およびERANGE。 POSIXではさらに多くのことが指定されています。これらをmain()からの戻りコードとして(またはexit()への引数として)使用しないでください。

2
user2371524

通常、Linuxプログラムは、成功した場合は0を返し、失敗した場合はゼロ以外を返します。いくつかの例外があります(たとえば、一致が見つかったかどうかを表す値を持つgrep)。これは、bashプロンプトでtrueが0、falseが1と定義されているため、スクリプトが簡単になるためです。

somecmd && action "if succesful"

しかし、それはプログラムそのものです。プログラム内のコードの場合、多くの場合、規則が混在しています。一般的な方法は、成功した場合は0(または正)を返し、失敗した場合は負を返すことです。この背後にある理由は、すべての命令セット(私が知っている)には、ゼロの場合は分岐、またはゼロ未満の場合は分岐の命令があるためです。つまり、比較を行う命令は1つだけです。比較を行ってから、比較が一致した場合は分岐する必要はありません)。

1
HardcoreHenry

errnoは、エラー番号で設定するグローバル変数です。慣例では、errnoを設定してから、負の数(通常は負の数)を返します。負の戻り値は、errnoをチェックする必要があることを示します。あなたの例を使用すると(そしてそれを関数に入れると)、それは次のようになります:

int allocate_buffer(char *buffer) {
    buffer = malloc(1024);
    if (buffer == NULL) {
        errno = ENOMEM;
        return -1;
    }
    return 0;
}

呼び出し元は、戻り値に基づいてエラーが発生したかどうかを認識し、errnoをチェックしてエラーが何であるかを確認し、そこからどのように進めるかを決定します。

0